除了ImageView和srcCompat之外,如何使用带有View的矢量drawable?

raz*_*zle 39 android android-support-library android-vectordrawable

app:srcCompatImageView允许向后兼容使用载体可绘的.但是,你怎么能与其他使用它们View小号之外ImageView?例如,TextView属性就像android:drawableLeft.

同时使用矢量drawable作为android:iconwith MenuItem导致崩溃,但有以下异常:

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)
Run Code Online (Sandbox Code Playgroud)

使用支持库23.2.0,如何解决此问题?

raz*_*zle 45

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

对于AppCompat用户,我们添加了一个opt-in API,通过AppCompatDelegate.setCompatVectorFromResourcesEnabled()重新启用资源支持Vector Drawables(23.2中的行为) - 请记住,这仍然会导致内存使用和问题问题更新配置实例,因此默认情况下禁用它.

更新:从版本23.3.0开始不再有效

对于AppCompat用户,由于版本23.2.0/23.2.1 [ https://code.google]中的实施中发现的问题,我们决定删除允许您使用Lollipop前设备上的资源使用矢量绘图的功能. com/p/android/issues/detail?id = 205236,https://code.google.com/p/android/issues/detail ?id = 204708 ].使用app:srcCompat和setImageResource()继续工作.

来自Android开发者Google+帖子


使用AppCompat和app:srcCompat是将矢量绘图集成到应用程序中最简单的方法.

那报价从官方博客帖子的支持库的23.2.0版本的发布.

该帖还提到以下内容:

你会发现直接引用外面的矢量drawables app:srcCompat会在Lollipop之前失败.然而,AppCompat不支持加载向量可绘制,当他们在另一抽拉容器被引用,如StateListDrawable,InsetDrawable,LayerDrawable,LevelListDrawable,和RotateDrawable.通过使用此间接,您可以在诸如TextView's android:drawableLeft属性的情况下使用向量drawable ,这通常不能支持向量drawable.

这转换为以下步骤:

步骤1:

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

第2步:

为先前创建的矢量drawable创建另一个代理可绘制资源.比如说,对于前一个ic_action_search_vector.xml,ic_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>
Run Code Online (Sandbox Code Playgroud)

如果您从另一个可绘制资源中引用了可绘制的矢量,则可以跳过此步骤,该资源将与View一起使用.

第3步:

使用drawable资源(此处ic_action_search.xml)引用vector drawable(ic_action_search_vector.xml)而不是vector drawable.对于菜单,它看起来像:

<item android:id="@+id/search"
        android:title="@string/search"
        android:icon="@drawable/ic_action_search"
        app:showAsAction="always"/>
Run Code Online (Sandbox Code Playgroud)

这是解决这个问题的方法!


Pet*_*aňa 29

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

activity_main.xml中

<android.support.v7.widget.AppCompatImageButton
    android:id="@+id/btnEnter"
    />
Run Code Online (Sandbox Code Playgroud)

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);
}
Run Code Online (Sandbox Code Playgroud)

此代码与此选择器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>
Run Code Online (Sandbox Code Playgroud)

UPDATE

如果使用API​​ 23未显示矢量drawable,则需要先将其转换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());
}
Run Code Online (Sandbox Code Playgroud)


Dav*_*and 18

矢量drawables可以在其他地方使用前Lollipop app:srcCompat,但它有一个价格.

我已经使这个图表有所帮助(对支持库23.4.0有效 - 至少 - 25.1.0).

VectorDrawable cheatsheet


Ars*_*hak 6

您可以通过编程方式在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);
Run Code Online (Sandbox Code Playgroud)

II.如果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);
Run Code Online (Sandbox Code Playgroud)

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