Verwenden von Android-Vektor-Drawables beim Absturz vor Lollipop

91

Ich verwende Vector Drawables in Android vor Lollipop und dies sind einige meiner Bibliotheken und Tool-Versionen:

  • Android Studio: 2.0
  • Android Gradle Plugin: 2.0.0
  • Build Tools: 23.0.2
  • Android Support Library: 23.3.0

Ich habe diese Eigenschaft in meiner App-Ebene hinzugefügt Build.Gradle

android {  
  defaultConfig {  
    vectorDrawables.useSupportLibrary = true  
   }  
}

Es ist auch erwähnenswert, dass ich ein zusätzliches Zeichenelement wie LayerDrawable (layer_list) verwende, wie im offiziellen Android-Blog ( Link hier ) angegeben, um Zeichenelemente für Vektorzeichen außerhalb von zu setzenapp:srcCompat

<level-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/search"/>
</level-list>

Sie finden direkt referenzierende Vektorzeichnungen außerhalb der App: srcCompat schlägt vor Lollipop fehl. AppCompat unterstützt jedoch das Laden von Vektor-Drawables, wenn auf sie in einem anderen Drawable-Container verwiesen wird, z. B. StateListDrawable, InsetDrawable, LayerDrawable, LevelListDrawable und RotateDrawable. Mit dieser Indirektion können Sie Vektor-Drawables in Fällen wie dem android: drawableLeft-Attribut von TextView verwenden, das normalerweise keine Vector-Drawables unterstützen kann.

Wenn ich app:srcCompatalles benutze , funktioniert alles gut, aber wenn ich benutze:

android:background
android:drawableLeft
android:drawableRight
android:drawableTop
android:drawableBottom

auf ImageView, ImageButton, TextViewoder EditTextvor dem Lutscher, wirft es ein expection:

Caused by: android.content.res.Resources$NotFoundException: File res/drawable/search_toggle.xml from drawable resource ID #0x7f0200a9
Behzad Bahmanyar
quelle
Mögliches Duplikat der Android-Vektorkompatibilität
Adam Hurwitz
Um zu sehen, wie VectorDrawable mit drawableLeft, drawableRight, drawableTop, drawableBottom verwendet wird, lesen Sie diese Antwort
Behzad Bahmanyar
Können Sie meine Antwort hier überprüfen? stackoverflow.com/a/40523623/2557258
Yazon2006
In meinem Fall waren Vactor Drawables nicht im richtigen Paket (offene Projektansicht). Ursprüngliche
murt

Antworten:

101

NEUESTES UPDATE - Jun / 2019

Die Support-Bibliothek hat sich seit der ursprünglichen Antwort etwas geändert. Jetzt kann sogar das Android-Plugin für Gradle das PNG beim Erstellen automatisch generieren. Im Folgenden sind zwei neue Ansätze aufgeführt, die heutzutage funktionieren sollten. Weitere Informationen finden Sie hier:

PNG-Erzeugung

Gradle kann zum Zeitpunkt der Erstellung automatisch PNG-Bilder aus Ihren Assets erstellen. Bei diesem Ansatz werden jedoch nicht alle XML-Elemente unterstützt . Diese Lösung ist praktisch, da Sie nichts in Ihrem Code oder in Ihrem build.gradle ändern müssen. Stellen Sie einfach sicher, dass Sie Android Plugin 1.5.0 oder höher und Android Studio 2.2 oder höher verwenden .

Ich verwende diese Lösung in meiner App und funktioniert einwandfrei. Kein zusätzliches build.gradle- Flag erforderlich. Es sind keine Hacks erforderlich. Wenn Sie zu / build / generate / res / pngs / ... gehen , werden alle generierten PNGs angezeigt.

Wenn Sie also ein einfaches Symbol haben (da nicht alle XML-Elemente unterstützt werden), funktioniert diese Lösung möglicherweise für Sie. Aktualisieren Sie einfach Ihr Android Studio und Ihr Android-Plugin für Gradle.

Support-Bibliothek

Wahrscheinlich ist dies die Lösung, die für Sie funktioniert. Wenn Sie hierher gekommen sind, bedeutet dies, dass Ihr Android Studio die PNGs nicht automatisch generiert. Ihre App stürzt also ab.

Oder vielleicht möchten Sie nicht, dass Android Studio überhaupt PNG generiert.

Anders als bei der "Auto-PNG-Generierung", die eine Teilmenge des XML-Elements unterstützt, unterstützt diese Lösung alle XML-Tags. Sie haben also volle Unterstützung für Ihre Vektorzeichnung.

Sie müssen zuerst Ihr build.gradle aktualisieren , um es zu unterstützen:

android {
  defaultConfig {
    // This flag will also prevents Android Studio from generating PNGs automatically
    vectorDrawables.useSupportLibrary = true
  }
}

dependencies {
  // Use this for Support Library
  implementation 'com.android.support:appcompat-v7:23.2.0' // OR HIGHER

  // Use this for AndroidX
  implementation 'androidx.appcompat:appcompat:1.1.0' // OR HIGHER
}

Und dann app:srcCompatanstelle von android:srcbeim Laden verwenden VectorDrawables. Vergiss das nicht.

Für TextView, wenn Sie die verwenden androidxVersion des Supports Library, können Sie app:drawableLeftCompat(oder rechts, oben, unten) stattapp:drawableLeft

Verwenden Sie im Fall von CheckBox/ anstelle von .RadioButtonapp:buttonCompatandroid:button

Wenn Sie die androidxVersion der Support-Bibliothek nicht verwenden und Ihr minSdkVersionis 17oder höher ist oder eine Schaltfläche verwendet, können Sie versuchen, programmgesteuert über zu setzen

Drawable icon = AppCompatResources.getDrawable(context, <drawable_id>);
textView.setCompoundDrawablesWithIntrinsicBounds(<leftIcon>,<topIcon>,<rightIcon>,<bottomIcon>);

UPDATE - Jul / 2016

Sie haben VectorDrawable in der
Android Support Library 23.4.0 wieder aktiviert

Für AppCompat-Benutzer haben wir eine Opt-In- API hinzugefügt, um die Unterstützung von Vector Drawables aus Ressourcen (das in 23.2 beschriebene Verhalten) über AppCompatDelegate.setCompatVectorFromResourcesEnabled (true) wieder zu aktivieren. Beachten Sie, dass dies weiterhin Probleme mit der Speichernutzung und verursachen kann Probleme beim Aktualisieren von Konfigurationsinstanzen, daher ist diese standardmäßig deaktiviert.

Möglicherweise ist die build.gradleEinstellung jetzt veraltet und Sie müssen sie nur für ordnungsgemäße Aktivitäten aktivieren (müssen jedoch getestet werden).

Um es jetzt zu aktivieren, müssen Sie Folgendes tun:

public class MainActivity extends AppCompatActivity {
    static {
        AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
    }

    ...
}

Ursprüngliche Antwort - Apr / 2016

Ich denke, dies geschieht, weil Support Vector in der neuesten Bibliotheksversion 23.3.0 deaktiviert wurde

Nach diesem POST :

Für AppCompat-Benutzer haben wir beschlossen, die Funktionalität zu entfernen, mit der Sie aufgrund von Problemen bei der Implementierung in Version 23.2.0 / 23.2.1 (AUSGABE 205236) Vektorzeichnungen aus Ressourcen auf Geräten vor Lollipop verwenden können . Verwenden von app: srcCompat und setImageResource () funktioniert weiterhin.

Wenn Sie das Problem AUSGABE 205236 besuchen , werden sie anscheinend in Zukunft aktiviert, aber das Speicherproblem wird nicht bald behoben:

In der nächsten Version habe ich eine Opt-In-API hinzugefügt, mit der Sie die entfernte VectorDrawable-Unterstützung wieder aktivieren können. Es gibt jedoch die gleichen Einschränkungen wie zuvor (Speichernutzung und Probleme bei der Aktualisierung der Konfiguration).

Ich hatte ein ähnliches Problem. In meinem Fall habe ich also alle Symbole zurückgesetzt, die Vektoren verwenden, die von Ressourcen- zu PNG-Bildern gezeichnet werden können (da das Speicherproblem auch dann weiterhin auftritt, wenn sie eine Option zum erneuten Aktivieren bieten).

Ich bin nicht sicher, ob dies die beste Option ist, aber es behebt meiner Meinung nach alle Abstürze.

W0rmH0le
quelle
1
Vielen Dank an @Guilherme P., aber warum haben Sie die vectorDrawables.useSupportLibrary = truePeropertie nicht entfernt , um die Generierung von PNGs zur Erstellungszeit wieder zu aktivieren ?
Behzad Bahmanyar
1
Dies wurde in der neuesten Version v2.3.3.0 aufgrund von Speicherproblemen deaktiviert. Auf diese Weise können sie zur Laufzeit kein PNG generieren ... Deshalb drucken sie im Logcat-Fehler: Unbekannter Tag-Vektor (oder so ähnlich).
W0rmH0le
4
Hier finden Sie die Anmeldeanweisungen plus.google.com/+AndroidDevelopers/posts/B7QhFkWZ6YX . Leider funktionieren VectorDrawables auf Pre-Lollipop-Geräten immer noch nicht. Ich bin in der Support Library 23.4.0 und habe sowohl 'generateDensities = []' als auch 'vectorDrawables.useSupportLibrary = true' in defaultConfig {} aufgerufen.
Adam Hurwitz
1
@AdamHurwitz Ich habe die Antwort aktualisiert. Es scheint, dass sie wieder aktiviert wurde. Allerdings müssen Sie sie jetzt anders aktivieren.
W0rmH0le
1
@juztcode Du hast recht. Sie sollten 'androidx.appcompat: appcompat: 1.1.0'
W0rmH0le
63

Ich hatte das gleiche Problem. Aber ich habe viel Forschung und Entwicklung betrieben und die Antwort bekommen.

Geben Sie für die Verwendung von Imageview und ImageButton app:srcCompat="@drawable/...." sowie für andere Ansichten wie Button und Textview anstelle der Verwendung "drawableLeft/right..."in XML programmgesteuert Drawables an:

button.setCompoundDrawablesWithIntrinsicBounds(AppCompatResources.getDrawable(mContext,R.drawable.ic_share_brown_18dp), null, null, null);

Und verwenden Sie "AppCompatResources", um das Drawable zu erhalten.

Shashank Kapsime
quelle
59

Um die anderen sehr guten Antworten zu erläutern , finden Sie hier ein Diagramm , das Ihnen helfen kann. Es ist gültig, wenn Sie eine Support-Bibliothek von 23.4.0 bis mindestens 25.1.0 haben.

VectorDrawable Cheatsheet

David Ferrand
quelle
1
Falls Sie versuchen, drawableLeft zu setzen, wickeln Sie es wie hier erwähnt in ein Drawable ein. medium.com/@chrisbanes/…
nizam.sp
Vielen Dank, dass diese Tabelle uns sehr hilft.
Silentsudo
39

Die Antwort von Guillherme P ist ziemlich großartig. Um eine kleine Verbesserung zu erzielen, müssen Sie diese Zeile nicht in jeder Aktivität hinzufügen. Wenn Sie sie einmal in der Anwendungsklasse hinzugefügt haben, funktioniert sie auch.

public class App extends Application {

static {
    AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
}

ERINNERN SIE SICH: Sie müssen die Verwendung der Support-Bibliothek in gradle noch aktiviert haben:

android {
  defaultConfig {
    vectorDrawables.useSupportLibrary = true
  }
}

Also, stellen Sie sicher , dass Sie eine Support - Bibliothek Version größer als v23.4 verwenden, wenn Google hinzugefügt , um die Unterstützung für Drawable Container zurück für VectorDrawables ( Release-Info )

Aktualisieren

Und für Codeänderungen:

  1. Stellen Sie sicher, dass Sie an app:srcCompatjedem Ort aktualisieren , an dem das android:srcAttribut akzeptiert wird (die IDE warnt Sie, wenn es wie für das <bitmap>Tag ungültig ist ).
  2. Für drawableLeft, drawableStart, drawableRight, drawableEndAttribute verwendet in TextViewund ähnliche Ansichten, werden Sie sie haben jetzt programmatisch zu setzen. Ein Beispiel für die Einstellung drawableStart:

    Drawable drawable = AppCompatResources.getDrawable(
            getContext(),
            R.drawable.your_vector_drawable);
    
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
        textView.setCompoundDrawablesRelativeWithIntrinsicBounds(drawable, null, null, null);
    }
Benny
quelle
Denken Sie daran, dass Sie die Verwendung der Unterstützungsbibliothek für Vektor-Drawables in gradle aktivieren müssen: vectorDrawables.useSupportLibrary = true
Benny
2
Ja. Ich weiß. Es ist jedoch ein Wrapper erforderlich, damit Vektor-Drawables als Drawables für TexViews funktionieren. Daher ist diese Antwort unvollständig.
Cesards
1
Gute Antwort. Es eignet sich besonders für Apps, bei denen alle Aktivitäten auf einer benutzerdefinierten Basisaktivität basieren.
Hong
14

Ich hatte das gleiche Problem. Und beheben Sie es durch Entfernen

vectorDrawables.useSupportLibrary = true

Meine Zielversion ist 25 und die Support-Bibliothek ist

 compile 'com.android.support:appcompat-v7:25.3.1'
Rajesh Nasit
quelle
1
das hat bei mir funktioniert. Vielen Dank. Ich habe das gerade entferntvectorDrawables.useSupportLibrary = true
Android Mediocre
Ich denke, das ist nicht der richtige Weg, so oder so habe ich deine Antwort abgelehnt. !!
Harish Reddy
Danke dir. funktioniert nicht für meine App. Alle Vektorzeichnungen funktionieren weiterhin, wenn sie entfernt wurden. Die App verwendet com.android.support:appcompat-v7:28.0.0
Hong
10

VectorDrawables auf Pre-Lollipop sollten ohne Verwendung einwandfrei funktionieren

AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);

Wenn Sie VectorDrawables in ImageViews verwenden möchten, können Sie das Attribut verwenden, srcCompatund es funktioniert, in Buttons oder TextViews jedoch nicht. Daher müssen Sie das Drawable in ein InsetDrawable oder ein LayerDrawable einbinden. Es gibt noch einen anderen Trick, den ich entdeckt habe: Wenn Sie Datenbindung verwenden, können Sie dies tun:

android:drawableLeft="@{@drawable/vector_ic_access_time_24px}"
android:drawableStart="@{@drawable/vector_ic_access_time_24px}"

Das wird auf magische Weise funktionieren. Ich habe nicht untersucht, was hinter den Kulissen passiert, aber ich denke, dass TextView die Methode getDrawable von AppCompatResources oder ähnlichem verwendet.

cesards
quelle
Wie stelle ich ein Vektorbild im Selektor ein?
Tushar Gogna
nach dem Setzen von vectorDrawables.useSupportLibrary = true in gradle default und AppCompatDelegate.setCompatVectorFromResourcesEnabled (true); in aktivität beim erstellen Um einen Absturz mit Android zu vermeiden : drawableleft in Textansicht , setzen Sie drawble programmatisch links in die Textansicht, zum Beispiel: textview.setCompoundDrawablesWithIntrinsicBounds (R.drawable.movie, 0, 0, 0);
Afjalur Rahman Rana
7

Viel F & E, endlich diese Lösung für Abstürze auf Pre-Lollipop-Geräten.

Für die Bildansicht

  • Verwenden Sie app: srcCompat anstelle von android: src

Für TextView / EditText

  • Entfernen Sie drawableleft , drawableright .... und setzen Sie es aus dem zeichnbaren Java-Code.

txtview.setCompoundDrawablesWithIntrinsicBounds (AppCompatResources.getDrawable (EventDetailSinglePage.this, R.drawable.ic_done_black_24_n), null, null, null);

Für Build.gradle

vectorDrawables.useSupportLibrary = true

Jatin Mandanka
quelle
1
Es war die einzigartige Lösung, die mit TextInputEditText funktioniert hat.
Heronsanches
1
Ehrfürchtig, dies ist mein Problem gelöst. Diese Antwort sollte akzeptiert werden.
DJtiwari
5

Für alle, die auf Android Gradle 3.0 und höher aktualisieren, ist es nicht erforderlich, zu verwenden AppCompatDelegate.setCompatVectorFromResourcesEnabled(true)oder festzulegen vectorDrawables.useSupportLibrary = true(dies führt zu Problemen) und zu verwenden app:srcCompat, es funktioniert einfach.

Nehmen Sie sich zwei Tage Zeit, um dies herauszufinden, und finden Sie keine verwandten Dokumente in den Google-Dokumenten ...

Geng Jiawen
quelle
Interessanterweise verwende ich Gradle 3.3.0 und diese Lösung funktioniert. Android Studio fordert mich jedoch weiterhin auf, set vectorDrawables.useSupportLibrary = true zu aktivieren.
Masterwok
5

Einfachste Verwendung:

app:drawableRightCompat ="@drawable/ic_mobilelogin"
app:drawableEndCompat="@drawable/ic_mobilelogin"
app:srcCompat="@drawable/ic_mobile"

und ... nur app:**Compatzur Kompatibilität verwenden. Fügen Sie auch Unterstützung hinzu für build.gradle(Modul)

android {
   defaultConfig {
       vectorDrawables.useSupportLibrary = true
   }
}
Hamed Jaliliani
quelle
App: drawableEndCompat und App: drawableRightCompat ist so ziemlich das Gleiche, wenn es Englisch ist
Hossam Hassan
2

Ich verwende VectorDrawables auf Pre-Lollipop-Geräten und gehe folgendermaßen vor:

Schritt 1: Fügen Sie dies in Ihre App-Ebene ein.

android {
  defaultConfig {
    vectorDrawables.useSupportLibrary = true
  }
}

Schritt 2:

Fügen Sie dies in Ihre Anwendungsklasse ein und vergessen Sie nicht, Ihre Anwendungsklasse in der Manifestdatei zu registrieren.

public class App extends Application {
    static {
        AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
    }
}

Schritt 3:

Holen Sie sich VectorDrawables mit,

imageView.setImageDrawable(ContextCompat.getDrawable(this, R.drawable.my_vector_drawable));
Parag Kadam
quelle
2

Nach Verwendung des folgenden Codes.

android {
  defaultConfig {
  vectorDrawables.useSupportLibrary = true  
                }
        }




public class App extends Application {
static {
    AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
}}

Dennoch besteht ein Vektorbildproblem für die folgenden Attribute

DrawableEnd, DrawableStart, DrawableTop, DrawableBottom, Hintergrund

In diesem Fall folgen Sie bitte den nachstehenden Anweisungen. Verwenden Sie anstelle der direkten Referenzierung des Vektorbilds das Selektor-Tag als Zwischenzeichnung.

Beispiel:

ic_warranty_icon.xml

<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="17dp"
android:height="24dp"
android:autoMirrored="true"
android:viewportWidth="17"
android:viewportHeight="24">

<path
    android:fillColor="#fff"
    android:pathData="M10.927,15.589l-1.549,0.355a7.47,7.47 0,0 1,-0.878 0.056c-4.136,0 -7.5,-3.364 -7.5,-7.5s3.364,-7.5 7.5,-7.5 7.5,3.364 7.5,7.5c0,3.286 -2.126,6.078 -5.073,7.089zM8.5,2a6.508,6.508 0,0 0,-6.5 6.5c0,3.583 2.917,6.5 6.5,6.5s6.5,-2.917 6.5,-6.5 -2.917,-6.5 -6.5,-6.5z" />

safe_ic_warranty_icon.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/ic_warranty_icon"  />
</selector>

Ihre Textansicht / Ihr Layout.

<TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:drawableStart="@drawable/ic_warranty_icon"
       />


<LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@drawable/ic_warranty_icon"
       />
Rajesh Gr
quelle
Vielen Dank !!! Für Hintergrundeigenschaften funktionierte das Hinzufügen eines Selektors dazwischen anstelle der direkten Verwendung eines Vektorzeichens für die Pre-Lollipop-API (19).
Ankur
In meinem Fall funktioniert dies immer noch nicht für API (16), selbst wenn es mitselector
mochadwi
1

Wir haben 3 Dinge ausprobiert

vectorDrawables.useSupportLibrary = true

Festlegen von setCompatVectorFromResourcesEnabled in der Anwendungsklasse

static {
    AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
}

Und verwenden app:srcCompat

Aber auch danach scheiterte es mit

Resources$NotFoundException: File res/drawable/$my_icon__0.xml from color state list resource ID #0x7f080008

Dann stellten wir fest, dass unser SVG ein Gradient-Tag hatte. Das Konvertieren des Gradienten-Tags in einzelne Pfade für die unten stehende API <= 23 und die Verwendung derselben SVG-API> = 24 hat funktioniert.

Hilfe von dieser Antwort erhalten https://stackoverflow.com/a/47783962/2171513

Aalap
quelle
Ich weiß nicht, warum niemand dies befürwortet, aber dies könnte tatsächlich die Lösung für mein Problem sein. Vielen Dank
DevMike01
0

Überlappen Sie einfach den Vektor, der auf die Statusliste gezeichnet werden kann, und das Problem wird gelöst

Zum Beispiel haben Sie einen Pfeil mit einem Pfeil nach hinten:

ic_back_arrow.xml

Ja, Sie sollten es mit der Layer-Liste xml (ic_back_arrow_vector_vector.xml) überlappen:

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/ic_back_arrow"/>
</layer-list>

Weil Logik:

vectorDrawables.useSupportLibrary = true

und

AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);

wird Ihnen auf einigen China-Geräten und älteren Samsung-Geräten nicht helfen. Wenn Sie sie nicht überlappen, schlägt dies fehl.

mr.boyfox
quelle
0

Ich hatte stundenlang damit zu kämpfen.

Ich habe alles versucht, was mir diese Antworten sagten, aber meine App hat nicht aufgehört zu stürzen. Ich habe diese Zeile gelöscht: app:srcCompat="@drawable/keyboard"und meine App stürzte nicht mehr ab. und als ich dasselbe wieder hinzufügte, fing es wieder an zu stürzen. Also habe ich beschlossen, diese Datei zu öffnen, und in der ersten Zeile wurde ein Fehler angezeigt

"Die zeichnbare 'Tastatur' hat keine Deklaration im Basis-Zeichnungsordner. Dies kann zu Abstürzen führen.

Ich habe mit der rechten Maustaste auf die Datei geklickt und auf "Im Explorer anzeigen" geklickt. Sie befand sich nicht im Ordner "drawable", sondern im Verzeichnis "drawable-v24". Also habe ich es kopiert und in das zeichnbare Verzeichnis eingefügt und schließlich Abstürze beseitigt.

Fahad Maqsood Qazi
quelle
-2

Der Vorschlag von Guilherme P hat bei mir nicht funktioniert. Ich habe die Entscheidung getroffen, PNGs zu verwenden, bei denen ich Dinge außerhalb der App ausführen muss: srcCompat, dh drawableLeft, drawableRight usw. Dies war eine ziemlich einfache Änderung und weist keine potenziellen Speicherprobleme auf. AppCompatDelegate.setCompatVectorFromResourcesEnabled ( wahr); stellt vor.

Ryan Newsom
quelle
-3

Eine Alternative zu Bennys Antwort besteht darin, eine ActivitySuperklasse zu erstellen :

public abstract class VectorDrawableActivity extends AppCompatActivity {
  static {
    AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
  }

  //...
}

Jetzt verlängern VectorDrawableActivitystatt AppCompatActivity.

Code-Lehrling
quelle
@cesards Warum nicht?
Code-Apprentice