除了带有 srcCompat 的 ImageView 之外,如何将矢量绘图与 View 一起使用?

How to use vector drawables with View besides ImageView with srcCompat?

app:srcCompatImageView 允许向后兼容矢量绘图的使用。但是,除了 ImageView 之外,您如何将它们与其他 View 一起使用?例如,TextView 属性如 android:drawableLeft.

同时使用矢量可绘制对象作为 android:iconMenuItem 导致崩溃,并出现以下异常:

Fatal Exception: android.view.InflateException: Binary XML file line #2: Error inflating class <unknown>
   at android.view.LayoutInflater.createView(LayoutInflater.java:626)
   at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:702)
   at android.view.LayoutInflater.inflate(LayoutInflater.java:470)
   at android.view.LayoutInflater.inflate(LayoutInflater.java:398)
   at android.support.v7.view.menu.MenuItemImpl.setActionView(MenuItemImpl.java:621)
   at android.support.v7.view.menu.MenuItemImpl.setActionView(MenuItemImpl.java:40)
   at android.support.v4.view.MenuItemCompat.setActionView(MenuItemCompat.java:310)
   at android.support.v7.view.SupportMenuInflater$MenuState.setItem(SupportMenuInflater.java:465)
   at android.support.v7.view.SupportMenuInflater$MenuState.addItem(SupportMenuInflater.java:479)
   at android.support.v7.view.SupportMenuInflater.parseMenu(SupportMenuInflater.java:196)
   at android.support.v7.view.SupportMenuInflater.inflate(SupportMenuInflater.java:118)
   at com.example.niceapp.context.main.MainActivity.onCreateOptionsMenu(MainActivity.java:101)
   at android.app.Activity.onCreatePanelMenu(Activity.java:2578)

有了 Support Library 23.2.0,如何解决这个问题?

更新 2:他们添加了一个选项以在支持库 23.4.0 中再次启用它:

For AppCompat users, we’ve added an opt-in API to re-enable support Vector Drawables from resources (the behavior found in 23.2) via AppCompatDelegate.setCompatVectorFromResourcesEnabled() - keep in mind that this still can cause issues with memory usage and problems updating Configuration instances, hence why it is disabled by default.

更新: 这从版本 23.3.0

开始不再有效

For AppCompat users, we’ve decided to remove the functionality which let you use vector drawables from resources on pre-Lollipop devices due to issues found in the implementation in version 23.2.0/23.2.1 [https://code.google.com/p/android/issues/detail?id=205236, https://code.google.com/p/android/issues/detail?id=204708]. Using app:srcCompat and setImageResource() continues to work.

来自Android Developers Google+ post


Using AppCompat and app:srcCompat is the most foolproof method of integrating vector drawables into your app.

该引用来自支持库 23.2.0 版的官方blogpost

post 还提到了以下内容:

You’ll find directly referencing vector drawables outside of app:srcCompat will fail prior to Lollipop. However, AppCompat does support loading vector drawables when they are referenced in another drawable container such as a StateListDrawable, InsetDrawable, LayerDrawable, LevelListDrawable, and RotateDrawable. By using this indirection, you can use vector drawables in cases such as TextView’s android:drawableLeft attribute, which wouldn’t normally be able to support vector drawables.

这转化为以下步骤:

第 1 步:

创建或导入应用所需的矢量资源。例如,可以为搜索图标创建一个矢量可绘制对象并将其命名为 ic_action_search_vector.xml

第 2 步:

为之前创建的矢量可绘制对象创建另一个代理可绘制对象资源。比如说,对于之前的 ic_action_search_vector.xmlic_action_search.xml 可以创建为一个简单的 StateListDrawable,其中可以包含以下行:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/ic_action_search_vector"/>
</selector>

如果您从将与视图一起使用的另一个可绘制对象资源中引用了矢量可绘制对象,则可以跳过此步骤。

第 3 步:

使用引用矢量可绘制对象 (ic_action_search_vector.xml) 的可绘制资源(此处为 ic_action_search.xml),而不是直接使用矢量可绘制对象。对于菜单,它看起来像:

<item android:id="@+id/search"
        android:title="@string/search"
        android:icon="@drawable/ic_action_search"
        app:showAsAction="always"/>

这就是那个问题的解决方案!

对于 AppCompat 版本 23.3.0,其中没有通过选择器 XML(razzledazzle 接受的答案)的工作解决方案,我们可以通过编程方式完成此操作:

activity_main.xml

<android.support.v7.widget.AppCompatImageButton
    android:id="@+id/btnEnter"
    />

MainActivity.java

AppCompatImageButton image = (AppCompatImageButton) findViewById(R.id.btnEnter);
if (image != null) {
    VectorDrawableCompat vcAccept = VectorDrawableCompat.create(getResources(), R.drawable.vc_accept, getTheme());
    VectorDrawableCompat vcAcceptWhite = VectorDrawableCompat.create(getResources(), R.drawable.vc_accept_white, getTheme());

    StateListDrawable stateList = new StateListDrawable();
    stateList.addState(new int[]{android.R.attr.state_focused, -android.R.attr.state_pressed}, vcAccept);
    stateList.addState(new int[]{android.R.attr.state_focused, android.R.attr.state_pressed}, vcAcceptWhite);
    stateList.addState(new int[]{-android.R.attr.state_focused, android.R.attr.state_pressed}, vcAcceptWhite);
    stateList.addState(new int[]{}, vcAccept);

    image.setImageDrawable(stateList);
}

此代码等效于此选择器 xml:

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_focused="true" android:state_pressed="false" android:drawable="@drawable/vc_accept" />
    <item android:state_focused="true" android:state_pressed="true" android:drawable="@drawable/vc_accept_white" />
    <item android:state_focused="false" android:state_pressed="true" android:drawable="@drawable/vc_accept_white" />
    <item android:drawable="@drawable/vc_accept" />
</selector>

更新

如果使用 API 23 未显示矢量可绘制对象,您需要先将 VectorDrawable 转换为常规 Drawable。如果你想使用 setCompoundDrawablesWithIntrinsicBounds 你需要这样做,但对于 StateListDrawable 我不需要。

Drawable icon;
if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
    icon = VectorDrawableCompat.create(getResources(), R.drawable.vc_icon, getContext().getTheme());
} else {
    icon = getResources().getDrawable(R.drawable.vc_icon, getContext().getTheme());
}

Android 5.0(API 级别 21)及更高版本提供矢量绘图支持。如果您的应用程序的最低 API 级别较低,Vector Asset Studio 会将矢量可绘制文件添加到您的项目中;此外,在构建时,Gradle 以各种分辨率创建 PNG 光栅图像。 Gradle 生成由领域特定语言 (DSL) generatedDensities 属性 在 build.gradle 文件中指定的 PNG 密度。要生成 PNG,构建系统需要 Android Gradle 1.5.0 或更高版本的插件。

如果您在 gradle 中加入,则情况并非如此 vectorDrawables.useSupportLibrary = 真

要么设置为 false,要么完全删除该行,您的所有向量都将按原样工作。但是对于 android 的旧版本,他们将能够依赖转换后的 PNG

您可以通过编程方式在 TextView 中添加 Vector Drawable。利用 VectorDrawableCompat 添加 drawableLeft/ drawableRight /drawableTop/ drawableBottom/ drawableStart/ drawableEnd.

步骤:

我。如果 TextView 在 Activity 内:

TextView tvUserName= (TextView)findViewById(R.id.et_username_or_email);
VectorDrawableCompat drawableCompat=VectorDrawableCompat.create(getResources(), R.drawable.layer_list_ic_user, tvUserName.getContext().getTheme());
tvUserName.setCompoundDrawablesRelativeWithIntrinsicBounds(drawableCompat, null, null, null);

二。如果 TextView 在 Fragment 中:

TextView tvUserName= (TextView )view.findViewById(R.id.et_username_or_email);
VectorDrawableCompat drawableCompat=VectorDrawableCompat.create(getActivity().getResources(), R.drawable.layer_list_ic_user, tvUserName.getContext().getTheme());
tvUserName.setCompoundDrawablesRelativeWithIntrinsicBounds(drawableCompat, null, null, null);

有关 VectorDrawableCompat 的更多信息,请参阅此 link

矢量绘图可以在 app:srcCompat 以外的其他地方使用 pre-Lollipop,但它是有代价的。

我已经 this diagram 提供帮助(对支持库 23.4.0 至 - 至少 - 25.1.0 有效)。

我正在使用新的支持库,我所要做的就是:

compile 'com.android.support:appcompat-v7:25.1.1'

在 Build.gradle 文件中

 defaultConfig {

    vectorDrawables.useSupportLibrary = true
}

现在,无论您在哪里使用类似片段,activity 或适配器,都将其用作 class

中的第一行
static {
    AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
}

之后像以前一样使用,something.xml

<ImageView
    android:id="@+id/ivMainNavigationIcon"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />

Something.java

thumbIcon.setImageDrawable(ContextCompat.getDrawable(context,R.drawable.ic_check_circle_black_24dp));

或者如果你有需要动态设置的drawable id

thumbIcon.setImageDrawable(ContextCompat.getDrawable(context,drawableID));

Form android studio 3.0.0 android:src 不支持矢量图像,小于 21 时出现异常。使用 app:srcCompat 作为矢量图像。将所有矢量图像文件保存在 drawable 文件夹中。

android {  
   defaultConfig {  
     vectorDrawables.useSupportLibrary = true  
    }  
 }

And in application class define this:

@Override
public void onCreate() {
    super.onCreate();
    AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
}

Now you can use your .xml file. Don't forget to user this link: xmlns:app="http://schemas.android.com/apk/res-auto"

<RelativeLayout
    android:id="@+id/counterValuePanel"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:srcCompat="@drawable/ic_cart_notify"/>
</RelativeLayout>

现在您可以使用 app:srcCompat="@drawable/ic_cart_notify" 但如果您尝试在 android:background 或 android:drawableLeft 中使用,则会出现 "Error inflating" 异常.为此,创建一个新的包装可绘制 .xml 文件,ic_cart_notify 是矢量图标。

<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/ic_cart_notify"/>
</layer-list>

大豆说的对。因此,如果您想使用 VectorDrawables 视图的选择器,您需要添加:

    static {
    AppCompatDelegate.setCompatVectorFromResourcesEnabled(trfor);
}

每个 Activity 您想要在版本低于 Android 的设备上使用 VectorDrawables 5.

set vector drawable to side drawable in textview in android

AppCompatTextView now 支持 app:drawableLeftCompat, app:drawableTopCompat, app:drawableRightCompat, app:drawableBottomCompat, app:drawableStartCompatapp:drawableEndCompat 复合绘图,支持向后移植的绘图类型,例如 VectorDrawableCompat.

将此包含在您的 gradle 文件中

implementation 'androidx.appcompat:appcompat:1.1.0-alpha01'

在您的文本视图中,您可以使用

app:drawableLeftCompat
app:drawableStartCompat