【问题标题】:Android Selector Drawable with VectorDrawables srcCompat带有 VectorDrawables srcCompat 的 Android Selector Drawable
【发布时间】:2016-08-12 23:14:51
【问题描述】:

我遇到了与 VectorDrawables 的新向后兼容性问题。 在支持库 23.2 中,引入了一个向后兼容 Android VectorDrawables 的新功能。

我有一个分配给 SelectorDrawable 的 ImageView。这个 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>

所有可绘制对象都是矢量 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 一起使用,则一切正常。所以我猜这是 SelectorDrawable 和兼容性的问题。

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

速览:

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

【问题讨论】:

  • 在 23.3 版中删除了对从资源中加载矢量可绘制对象的支持 - plus.google.com/+AndroidDevelopers/posts/iTDmFiGrVne
  • 但是:“使用 app:srcCompat 和 setImageResource() 继续工作”所以 app:srcCompat 在 23.3 中仍然可以工作。还是不行?
  • 是的,使用 app:srcCompat 仍然有效,因此您可以将一个 VectorDrawable 设置为 ImageView。然而,不幸的是,在 xml 状态列表中加载可绘制对象不再有效

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


【解决方案1】:

正如@Jahnold 在问题评论中提到的那样,对从 xml 状态 xml 列表中加载可绘制矢量的支持已在 23.3 中删除。

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

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

如果您使用状态列表矢量可绘制对象,该方法是合适的,它不仅可以区分颜色,还可以区分图形,因此您需要创建几个不同的 xml 文件。然后您可以通过编程方式创建StateListDrawable,如answer 所示。

【讨论】:

  • 我花了一个小时发现button_tint.xml文件应该放在/res/color文件夹下。所以,别忘了。
  • 您可能不应该在可绘制对象本身中定义色调和色调模式。这限制了可绘制对象的可重用性。如果设计师决定更改颜色,或者使用相同的图标但颜色不同,则需要复制可绘制对象,而不是使用样式等对其进行着色
  • @Ghristopher Perry 在这种情况下,您可以使用第二种方法。
  • 这行得通!确保使用 android:tint,而不是 app:tint。
【解决方案2】:

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

支持库 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(代号 Lollipop,API 级别 21)的设备上使用 VectorDrawables 的每个 Activity:

static {
    AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
}

因此,您现在可以在 DrawableContainers 中使用 VectorDrawables,但它仍然会导致上述来源中提到的一些问题,因此请谨慎使用。

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

【讨论】:

  • 另外,以下错误报告可能会有所帮助:code.google.com/p/android/issues/…
  • “您需要将其添加到您想在低于 Android 5 的设备上使用 VectorDrawables 的每个活动中”不正确,即使对于 android 15,我们也需要这样做
  • @stallianz Android 5 等于 API 级别 21。不要将发布版本与 API 版本混淆。
  • 你在哪里使用AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);?我已经使用它但我现在收到错误XmlPullParserException: Binary XML file line #4: invalid drawable tag vector
  • @F43nd1r 至少称它为 android 5.0。 Android 5 是模棱两可的。
【解决方案3】:

观看支持库中的新功能 - 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>

还有返回着色drawable的java方法:

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));

【讨论】:

    【解决方案4】:

    以下更改工作正常。

    static {
     AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
    }
    

    在应用程序类中添加。
    app build.gradle 在 defaultConfig 中

    vectorDrawables.useSupportLibrary = true
    

    【讨论】:

    • 在我的情况下,我设置了 useSupportLibrary,但我在 api 16 上的应用程序崩溃了,因为我设置了带有 svg 的可绘制状态列表。所以,看来,我必须同时使用这两种变体
    【解决方案5】:

    我建议使用这种解决方法来根据状态更改颜色: 设置一个普通的白色 VectorDrawable,并让 tint 具有颜色选择器。

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

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

    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>
    

    【讨论】:

      【解决方案6】:
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-04-26
      • 2013-05-26
      • 1970-01-01
      相关资源
      最近更新 更多