70

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

我有一个 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>

所有可绘制对象都是矢量 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
  • 支持图书馆 23.3.0
  • vectorDrawables.useSupportLibrary = true
  • 摇篮 2.0
4

6 回答 6

70

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

借助支持库 23.4.0,重新启用了对来自 Ressources 的 VectorDrawables 的支持:Android 支持库 23.4.0 现在可用

您可以在 Google I/O 2016 的此演员表中找到更多信息: 支持库中的新增功能 - Google I/O 2016

您需要将此添加到要在 Android 5.0(代号 Lollipop,API 级别 21)以下的设备上使用 VectorDrawables 的每个 Activity 中:

static {
    AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
}

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

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

于 2016-06-24T11:53:45.823 回答
64

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

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

1. 使用色调

如果所选状态列表中的可绘制对象仅因颜色而异,则该方法适用。

首先,只创建一个带有 tint 和 white 的可绘制矢量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所示以编程方式创建。

于 2016-04-27T09:49:56.720 回答
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>

并且有返回着色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));
于 2016-11-07T17:30:12.623 回答
4

使用以下更改正常工作。

static {
 AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
}

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

vectorDrawables.useSupportLibrary = true
于 2018-02-03T12:21:07.583 回答
2

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

即使在使用 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
    }
}

资源/布局/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>
于 2020-01-06T09:04:38.447 回答
0

利用animated-selector

例子

https://github.com/alexjlockwood/adp-delightful-details

https://www.androiddesignpatterns.com/2016/11/introduction-to-icon-animation-techniques.html

animated-vector使用此工具创建文件

https://shapeshifter.design/

于 2020-12-23T18:15:01.730 回答