Android Selector使用VectorDrawables srcCompat绘制

时间:2016-04-20 10:29:45

标签: android vector android-support-library appcompat-v7-r23 android-vectordrawable

我遇到了与VectorDrawables新的向后兼容性问题。 在支持库中,23.2是一个新功能,用于向后兼容所生成的Android VectorDrawables。

我有一个ImageView,它是一个分配给的SelectorDrawable。这个Drawable拥有几个VectorDrawables所以我认为我应该使用app:srcCompat来兼容。但它在我的Galaxy S2上不适用于android 4.1.2。

<?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都是vector xml文件。

将此SelectorDrawable与srcCompat一起使用时,出现此错误:

  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中的一个矢量drawable,一切正常。所以我猜这是SelectorDrawable和兼容性的问题。

有没有人遇到同样的问题并找到解决方案,或者目前无法在Android 5之前的SelectorDrawables中使用VectorDrawables?

简要说明:

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

6 个答案:

答案 0 :(得分:63)

自从我问这个问题后,有些事情发生了变化,所以我会自己回答。

借助支持库23.4.0,重新启用了对来自Ressources的VectorDrawables的支持:Android Support Library 23.4.0 available now

您可以在Google I / O 2016的演员阵容中找到更多相关信息: What's new in the support library - Google I/O 2016

你需要将这个添加到你想在Android 5.0以下的设备上使用VectorDrawables的每个Activity(Codename Lollipop,API level 21):

static {
    AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
}

所以你现在可以在DrawableContainers中使用VectorDrawables,但它仍然会引起上面提到的一些问题,所以请谨慎使用。

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

答案 1 :(得分:53)

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

但是,我找到了几种可以提供帮助的方法。

<强> 1。使用色调

如果来自所选状态列表的可绘制列表仅通过颜色区别,则该方法是合适的。

首先,只创建一个带有色调和白色fillColor的可绘制矢量:

<?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>

其次,创建放置在button_tint.xml

中的颜色状态列表res/color
<?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。硬编码创建StateListDrawable

如果您使用状态列表矢量drawables,这种方法是合适的,这不仅可以区分颜色,还可以通过图形区别,因此您需要创建多个不同的xml文件。然后,您可以按answer

中所示的方式以编程方式创建StateListDrawable

答案 2 :(得分:7)

观看支持库中的新功能 - Google I / O 2016 后,我注意到AppCompatResources课程中有一种有用的方法。这是AppCompatResources#getColorStateList(Context context, int resId)。在这种方法的帮助下,我实现了带有矢量绘图的选择器。这是我的颜色选择器文件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方法返回tinted 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));

答案 3 :(得分:2)

以下更改正常工作。

static {
 AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
}

在应用程序类中添加 default buildConfig中的app build.gradle

vectorDrawables.useSupportLibrary = true

答案 4 :(得分:1)

我建议采用以下变通方法来根据状态进行颜色更改: 设置一个普通的白色VectorDrawable,并使颜色具有颜色选择器。

经过测试,即使在使用Android API 16的模拟器上也可以使用,并且即使在gradle中设置了“ vectorDrawables.useSupportLibrary = true”,它也可以正常工作。

示例:启用第一个视图,然后禁用第二个视图:

enter image description here

MainActivity.kt

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        disabledSendMessageButton.isEnabled = false
    }
}

res / layout / activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent" android:layout_height="match_parent" android:clipChildren="false"
    android:clipToPadding="false" android:gravity="center" android:orientation="vertical" tools:context=".MainActivity">

    <androidx.appcompat.widget.AppCompatImageView
        android:id="@+id/sendMessageButton" android:layout_width="wrap_content" android:layout_height="wrap_content"
        android:clickable="true" android:focusable="true" android:foreground="?attr/selectableItemBackgroundBorderless"
        android:minWidth="?attr/actionBarSize" android:minHeight="?attr/actionBarSize" android:padding="8dp"
        android:scaleType="centerInside" app:srcCompat="@drawable/ic_baseline_send_24" app:tint="@color/color_selector"
        tools:targetApi="m" />

    <androidx.appcompat.widget.AppCompatImageView
        android:id="@+id/disabledSendMessageButton" android:layout_width="wrap_content"
        android:layout_height="wrap_content" android:clickable="true" android:focusable="true"
        android:foreground="?attr/selectableItemBackgroundBorderless" android:minWidth="?attr/actionBarSize"
        android:minHeight="?attr/actionBarSize" android:padding="8dp" android:scaleType="centerInside"
        app:srcCompat="@drawable/ic_baseline_send_24" app:tint="@color/color_selector" tools:targetApi="m" />
</LinearLayout>

res / color / color_selector.xml

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:color="@android:color/secondary_text_dark" android:state_enabled="false" />
    <item android:color="@color/colorPrimary" />
</selector>

res / drawable / ic_baseline_send_24.xml

<vector android:height="24dp" android:tint="#FFFFFF"
    android:viewportHeight="24.0" android:viewportWidth="24.0"
    android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
    <path android:fillColor="@android:color/white" android:pathData="M2.01,21L23,12 2.01,3 2,10l15,2 -15,2z"/>
</vector>

答案 5 :(得分:0)