web-dev-qa-db-ja.com

Android VectorDrawables srcCompatを使用したセレクターDrawable

VectorDrawablesとの新しい下位互換性に関する問題に直面しています。サポートライブラリ23.2には、Android VectorDrawablesが導入されたとの下位互換性のための新しい機能がありました。

SelectorDrawableが割り当てられたImageViewがあります。このDrawableは複数のVectorDrawableを保持しているため、互換性のために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ファイルです。

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でベクタードロウアブルの1つを使用すると、すべて正常に動作します。だから、SelectorDrawableと互換性の問題だと思います。

誰も同じ問題を抱えていて解決策を見つけましたか、現在、Android 5より前のSelectorDrawablesでVectorDrawablesを使用することはできませんか?

クイックファクト:

  • ターゲットAPIのコンパイル23
  • Libraray 23.3.0をサポート
  • vectorDrawables.useSupportLibrary = true
  • Gradle 2.0
59
marilion91

この質問をしてからいくつかのことが変わったので、自分で答えます。

サポートライブラリ23.4.0では、RessourcesからのVectorDrawablesのサポートが再び有効になりました。 Androidサポートライブラリ23.4.0が利用可能になりました

このキャストの詳細については、Google I/O 2016をご覧ください。 サポートライブラリの新機能-Google I/O 2016

Android 5.0(コード名Lollipop、APIレベル21)以下のデバイスでVectorDrawablesを使用するすべてのアクティビティにこれを追加する必要があります。

static {
    AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
}

したがって、DrawableContainersでVectorDrawablesを使用できるようになりましたが、上記のソースに記載されているように問題が発生する可能性があるため、注意して使用してください。

私はこれまでアプリでこの機能を再度有効にしませんでしたが、次のメジャーリリースで多くのアイコンをVectorDrawablesに変更し、このトピックをさらに掘り下げていきます。

64
marilion91

質問へのコメントで@Jahnoldが言及したように、xml state xmlリストからvector drawableをロードするサポートは23.3で削除されました。

しかし、役立ついくつかのアプローチを見つけました。

1。 Tintを使用する

この方法は、選択された状態リストのドロアブルが色のみで異なる場合に適しています。

まず、色合いと白のfillColorを含む1つのベクトルDrawableのみを作成します。

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

この方法は、色だけでなく図によっても異なる状態リストベクトルDrawableに使用する場合に適しているため、いくつかの異なるxmlファイルを作成する必要があります。次に、 answer に示すように、StateListDrawableをプログラムで作成できます。

53

サポートライブラリの新機能-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メソッドがあります:

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

以下の変更で正常に動作します。

static {
 AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
}

Applicationクラスに追加されました。
defaultConfig内のapp build.gradle

vectorDrawables.useSupportLibrary = true
2
Raja Peela