webentwicklung-frage-antwort-db.com.de

Android Selector Drawable with VectorDrawables srcCompat

Ich stehe vor einem Problem mit der neuen Abwärtskompatibilität mit VectorDrawables. In der Support Library 23.2 wurde eine neue Funktion zur Abwärtskompatibilität mit Android VectorDrawables eingeführt.

Ich habe eine ImageView, der ein SelectorDrawable zugewiesen ist. Dieses Drawable enthält mehrere VectorDrawables. Aus Kompatibilitätsgründen sollte ich app: srcCompat verwenden. Auf meinem Galaxy S2 mit 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>

Alle Drawables sind Vektor-XML-Dateien.

Bei Verwendung dieses SelectorDrawable mit srcCompat erhalte ich folgenden Fehler:

  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

mit Android: src ist noch schlimmer.

Wenn ich eine der Vektorzeichnungen mit app verwende: srcCompat funktioniert alles einwandfrei. Ich denke, es ist ein Problem mit dem SelectorDrawable und der Kompatibilität.

Hat jemand das gleiche Problem und fand eine Lösung oder ist es derzeit nicht möglich, VectorDrawables in SelectorDrawables vor Android 5?

Die schnellen Fakten:

  • Kompilieren der Ziel-API 23
  • Unterstützt Libraray 23.3.0
  • vectorDrawables.useSupportLibrary = true
  • Gradle 2.0
59
marilion91

einige Dinge haben sich geändert, seit ich diese Frage gestellt habe. Ich werde sie selbst beantworten.

Mit Support Library 23.4.0 wurde die Unterstützung für VectorDrawables aus Ressourcen wieder aktiviert: Android Support Library 23.4.0 ist jetzt verfügbar

Weitere Informationen dazu finden Sie in dieser Besetzung aus dem Google I/O 2016: Was ist neu in der Support-Bibliothek - Google I/O 2016

Sie müssen dies zu jeder Aktivität hinzufügen, in der Sie VectorDrawables auf folgenden Geräten verwenden möchten Android 5.0 (Codename Lollipop, API-Stufe 21):

static {
    AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
}

Sie können jetzt VectorDrawables in DrawableContainers verwenden, es kann jedoch dennoch zu Problemen kommen, wie in den obigen Quellen erwähnt. Gehen Sie daher vorsichtig vor.

Ich habe diese Funktion in meiner App bisher nicht wieder aktiviert, werde aber in meinem nächsten Haupt-Release viele meiner Symbole in VectorDrawables ändern und mich dann eingehender mit diesem Thema befassen.

64
marilion91

Wie @Jahnold im Kommentar zu Frage erwähnte, wurde die Unterstützung für das Laden von Vektoren, die aus einer XML-Status-XML-Liste gezogen werden können, in 23.3 entfernt.

Ich habe jedoch mehrere Ansätze gefunden, die helfen können.

1. Farbton verwenden

Der Ansatz ist geeignet, wenn sich die Zeichnungsobjekte aus der ausgewählten Statusliste nur farblich unterscheiden.

Erstellen Sie zunächst nur einen Vektor, der mit Farbton und Weiß fillColor gezeichnet werden kann:

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

Zweitens erstellen Sie eine Farbstatusliste button_tint.xml In 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>

Vergessen Sie nicht, folgende Zeilen zu build.gradle Hinzuzufügen, da der Ansatz bei alten Android Versionen) nicht funktioniert.

defaultConfig {
    vectorDrawables.useSupportLibrary = true
}

2. Hardcode-Erstellung StateListDrawable

Der Ansatz eignet sich, wenn Sie für die Zustandsliste Vektorzeichnungen verwenden, die sich nicht nur in der Farbe, sondern auch in der Zahl unterscheiden, sodass Sie mehrere verschiedene XML-Dateien erstellen müssen. Dann können Sie StateListDrawable programmgesteuert erstellen, wie in Antwort gezeigt.

53

Nach dem Anschauen von Was ist neu in der Support-Bibliothek - Google I/O 2016 ist mir eine nützliche Methode in der Klasse AppCompatResources aufgefallen. Dies ist AppCompatResources#getColorStateList(Context context, int resId). Mit Hilfe dieser Methode habe ich einen Selektor mit Vektorzeichen implementiert. Hier ist meine Farbauswahldatei 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>

Und es gibt Java Methode, die getönte Zeichen zurückgibt:

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

Sie können es wie unten gezeigt verwenden

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

Funktioniert gut mit den folgenden Änderungen.

static {
 AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
}

In der Anwendungsklasse hinzugefügt.
App build.gradle in defaultConfig

vectorDrawables.useSupportLibrary = true
2
Raja Peela