Android Selector Drawable mit VectorDrawables srcCompat

Lesezeit: 8 Minuten

Ich habe ein Problem mit der neuen Abwärtskompatibilität mit VectorDrawables. In der Support Library 23.2 wurde ein neues Feature zur Abwärtskompatibilität mit Android VectorDrawables eingeführt.

Ich habe eine ImageView, der ein SelectorDrawable zugewiesen ist. Dieses Drawable enthält mehrere VectorDrawables, daher dachte ich, ich sollte app:srcCompat aus Kompatibilitätsgründen verwenden. Aber es funktioniert nicht 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 der Verwendung dieses SelectorDrawable mit srcCompat erhalte ich diesen 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

Die Verwendung von android:src ist noch schlimmer.

Wenn ich eines der Vektor-Drawables mit app:srcCompat verwende, funktioniert alles einwandfrei. Ich denke also, es ist ein Problem mit dem SelectorDrawable und der Kompatibilität.

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

Die schnellen Fakten:

  • Ziel-API kompilieren 23
  • Bibliothek 23.3.0 unterstützen
  • vectorDrawables.useSupportLibrary = wahr
  • Klasse 2.0

  • Unterstützung für das Laden von Vektor-Drawables aus Ressourcen wurde in Version 23.3 entfernt – plus.google.com/+AndroidDevelopers/posts/iTDmFiGrVne

    – Jahnold

    20. April 2016 um 10:57 Uhr

  • Aber: “Die Verwendung von app:srcCompat und setImageResource() funktioniert weiterhin”, also sollte app:srcCompat in 23.3 noch funktionieren. oder nicht?

    – marilion91

    20. April 2016 um 11:11 Uhr

  • Ja, die Verwendung von app:srcCompat funktioniert immer noch, sodass Sie ein VectorDrawable auf eine ImageView setzen können. Das Laden der Drawables in eine xml-Zustandsliste funktioniert jedoch leider nicht mehr

    – Jahnold

    20. April 2016 um 11:25 Uhr

Benutzer-Avatar
Marion91

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

Mit Support Library 23.4.0 wurde die Unterstützung für VectorDrawables von Ressources wieder aktiviert: Android Support Library 23.4.0 jetzt verfügbar

Mehr Informationen dazu finden Sie in diesem Cast von der Google I/O 2016:
Neuigkeiten in der Support-Bibliothek – Google I/O 2016

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

static {
    AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
}

Sie können also jetzt VectorDrawables in DrawableContainers verwenden, aber es kann immer noch einige Probleme verursachen, wie in den obigen Quellen erwähnt, also verwenden Sie es mit Vorsicht.

Ich habe diese Funktion in meiner App bisher nicht wieder aktiviert, aber ich werde mit meiner nächsten großen Version viele meiner Symbole auf VectorDrawables umstellen und dann tiefer in dieses Thema eintauchen.

  • Auch der folgende Fehlerbericht könnte hilfreich sein: code.google.com/p/android/issues/…

    – Paul LeBeau

    29. Juni 2016 um 9:55 Uhr

  • “Sie müssen dies zu jeder Aktivität hinzufügen, bei der Sie VectorDrawables auf Geräten unter Android 5 verwenden möchten” stimmt nicht, wir brauchen das sogar für Android 15

    – Stallanz

    11. August 2016 um 15:09 Uhr

  • @stallianz Android 5 entspricht API-Level 21. Verwechseln Sie Release-Versionen nicht mit API-Versionen.

    – F43nd1r

    6. September 2016 um 12:55 Uhr

  • wo benutzt du AppCompatDelegate.setCompatVectorFromResourcesEnabled(true); ?Ich habe es benutzt, aber ich erhalte jetzt den Fehler XmlPullParserException: Binary XML file line #4: invalid drawable tag vector

    – Irgendwer irgendwo

    5. Oktober 2017 um 14:15 Uhr

  • @ F43nd1r Nun, nennen Sie es zumindest Android 5.0. Android 5 ist mehrdeutig.

    – hqzxzwb

    25. November 2017 um 4:05 Uhr

Benutzer-Avatar
Sergej Wassilenko

Wie @Jahnold im Kommentar zu der Frage erwähnte, wurde die Unterstützung für das Laden von Vector Drawable aus einer XML-Zustands-XML-Liste in 23.3 entfernt.

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

1. Verwendung von Tint

Der Ansatz ist geeignet, wenn sich die Drawables aus der ausgewählten Zustandsliste nur durch Farben unterscheiden.

Erstellen Sie zunächst nur einen Vektor, der mit Farbton und Weiß gezeichnet werden kann 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>

Erstellen Sie zweitens eine Farbzustandsliste button_tint.xml platziert 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, Folgelinien hinzuzufügen build.gradle oder der Ansatz funktioniert nicht auf alten Android-Versionen.

defaultConfig {
    vectorDrawables.useSupportLibrary = true
}

2. Hardcode-Erstellung StateListDrawable

Der Ansatz eignet sich, wenn Sie für die Zustandsliste Vektorzeichen verwenden, die sich nicht nur durch eine Farbe, sondern auch durch eine Figur unterscheiden, sodass Sie mehrere verschiedene xml-Dateien erstellen müssen. Dann können Sie erstellen StateListDrawable programmgesteuert, wie in einer Antwort gezeigt.

  • Ich verbringe eine Stunde, um das zu finden button_tint.xml Datei sollte unter platziert werden /res/color Mappe. Also, vergiss es nicht.

    – Nguyen Minh Binh

    30. Juni 2016 um 4:07 Uhr

  • Wahrscheinlich sollten Sie den Farbton und den Farbtonmodus nicht im Drawable selbst definieren. Dies schränkt die Wiederverwendbarkeit der Drawables ein. Wenn der Designer beschließt, die Farbe zu ändern oder dasselbe Symbol in anderen Farben zu verwenden, müssen Sie das Drawable duplizieren, anstatt es nur mit einem Stil usw. zu tönen

    – Christoph Perry

    11. Juli 2016 um 19:06 Uhr

  • @Ghristopher Perry In diesem Fall können Sie den zweiten Ansatz verwenden.

    – Sergej Wassilenko

    12. Juli 2016 um 8:13 Uhr

  • Das funktioniert! Stellen Sie sicher, dass Sie android:tint und nicht app:tint verwenden.

    – Eino Gourdin

    21. Februar 2020 um 8:26 Uhr

Benutzer-Avatar
Wolodymyr

Nach dem Anschauen Neuigkeiten in der Support-Bibliothek – Google I/O 2016 Mir ist eine nützliche Methode in der aufgefallen AppCompatResources Klasse. Das ist AppCompatResources#getColorStateList(Context context, int resId). Mit Hilfe dieser Methode habe ich einen Selektor mit Vektordrawables 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 eine Java-Methode, die getöntes Drawable 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

Ich schlage diese Problemumgehung vor, um die Farbänderung basierend auf dem Status vorzunehmen: Legen Sie ein normales, weißes VectorDrawable fest und lassen Sie den Farbton den Farbwähler haben.

Dies wurde getestet, um sogar auf einem Emulator mit Android API 16 zu funktionieren, und es funktioniert natürlich auch, wenn Sie “vectorDrawables.useSupportLibrary = true” in Gradle festlegen.

Beispiel: Die erste Ansicht ist aktiviert und die zweite deaktiviert:

Geben Sie hier die Bildbeschreibung ein

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>

Benutzer-Avatar
Isaak Osipovich Dunayevsky

verwenden animated-selector

Beispiel

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

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

schaffen animated-vector Datei mit diesem Tool

https://shapeshifter.design/

1246670cookie-checkAndroid Selector Drawable mit VectorDrawables srcCompat

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy