Androidselect器可用VectorDrawables srcCompat绘制

我面临与VectorDrawables新的向后兼容性问题。 在支持库中,23.2是与向量兼容的VectorDrawables的一个新function。

我有一个ImageView是一个SelectorDrawable分配给。 这个Drawable包含了几个VectorDrawables,所以我想我应该使用app:srcCompat来兼容。 但它不适用于Android 4.1.2我的Galaxy S2。

<?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:drawable="@drawable/ic_gps_fixed_24dp"android:state_activated="true" android:state_selected="true"></item> <item android:drawable="@drawable/ic_gps_not_fixed_24dp" android:state_activated="true" android:state_selected="false"></item> <item android:drawable="@drawable/ic_gps_not_fixed_24dp" android:state_activated="false" android:state_selected="true"></item> <item android:drawable="@drawable/ic_gps_off_24dp" android:state_activated="false" android:state_selected="false"></item> <item android:drawable="@drawable/ic_gps_not_fixed_24dp"></item> </selector> 

所有的drawables都是vectorxml文件。

当与srcCompat使用这个SelectorDrawable时,我得到这个错误:

  Caused by: android.content.res.Resources$NotFoundException: File res/drawable/ Caused by: android.content.res.Resources$NotFoundException: File res/drawable/ic_gps_fixed_24dp.xml from drawable resource ID #0x7f0201c1 at android.content.res.Resources.loadDrawable(Resources.java:1951) at android.content.res.Resources.getDrawable(Resources.java:672) at android.graphics.drawable.StateListDrawable.inflate(StateListDrawable.java:173) at android.graphics.drawable.Drawable.createFromXmlInner(Drawable.java:881).xml from drawable resource ID #0x7f0201c1 

使用android:src更糟。

如果我使用app:srcCompat中的一个vector绘图,所有工作正常。 所以我猜这是与SelectorDrawable和兼容性的问题。

有没有人有同样的问题,并find一个解决scheme,或者是目前不可能在Android 5之前在SelectorDrawables中使用VectorDrawables?

小知识:

  • 编译目标API 23
  • 支持Libraray 23.3.0
  • vectorDrawables.useSupportLibrary = true
  • Gradle 2.0

自从我问这个问题以来,有些事情已经改变了,所以我会自己回答。

通过Support Library 23.4.0,可以重新启用对Ressources的VectorDrawables的支持: Android支持库23.4.0现在可用

您可以从Google I / O 2016中find更多关于此内容的信息: 支持库中的新function – Google I / O 2016

您需要将此添加到您要在Android 5下的设备上使用VectorDrawable的每个活动:

 static { AppCompatDelegate.setCompatVectorFromResourcesEnabled(true); } 

所以你现在可以在DrawableContainers中使用VectorDrawables,但是它仍然可能导致上面提到的一些问题,所以谨慎使用它。

我到目前为止还没有在应用程序中重新启用这个function,但是我会在下一个主要版本中将很多图标更改为VectorDrawables,然后再深入探讨这个主题。

正如@Jahnold在问题的评论中提到的那样,在23.3中删除了从xml状态xml列表中加载vector的支持。

但是,我发现了几种可以帮助的方法。

1.使用色调

如果所选状态列表中的绘图仅由颜色区分,则该方法是合适的。

首先,创build只有一个可绘制的色彩和白色fillColorvector:

 <?xml version="1.0" encoding="utf-8"?> <vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24dp" android:height="24dp" android:viewportWidth="24" android:viewportHeight="24" android:tintMode="multiply" android:tint="@color/button_tint"> <path android:fillColor="#ffffff" android:pathData="M2.01 21L23 12 2.01 3 2 10l15 2-15 2z"/> <path android:pathData="M0 0h24v24H0z"/> </vector> 

其次,在res/color创build颜色状态列表button_tint.xml

 <?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:color="#555555" android:state_enabled="false"/> <item android:color="#6699dd"/> </selector> 

不要忘记添加后续行build.gradle或该方法不适用于旧的Android版本。

 defaultConfig { vectorDrawables.useSupportLibrary = true } 

2.硬编码创buildStateListDrawable

这种方法适合用于状态列表vector绘图,它们不仅仅是一个颜色,而且也是一个graphics,所以你需要创build几个不同的XML文件。 然后,您可以按照答案中所示以编程方式创buildStateListDrawable

在看了支持库中的新function – Google I / O 2016之后,我注意到AppCompatResources类中有一个有用的方法。 这是AppCompatResources#getColorStateList(Context context, int resId) 。 在这个方法的帮助下,我实现了带有vector绘制的select器。 这是我的颜色select器文件icon_selector

 <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:color="@color/red_selected" android:state_selected="true"/> <item android:color="@color/red_pressed" android:state_pressed="true"/> <item android:color="@color/red"/> </selector> 

有java方法返回着色drawable:

  private Drawable getTintedDrawable(@DrawableRes int drawableId) { Drawable drawable; if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { drawable = getResources().getDrawable(drawableId, getTheme()); } else { drawable = getResources().getDrawable(drawableId); } drawable = DrawableCompat.wrap(drawable); DrawableCompat.setTintList(drawable.mutate(), AppCompatResources.getColorStateList(this, R.color.selector_nav_bar_item_ico)); return drawable; } 

你可以像下面这样使用它

 yourImageView.setImageDrawable(getTintedDrawable(R.drawable.ic_vector_image));