Utilizzo di Drawables vettoriali Android su crash pre Lollipop


91

Sto usando i drawable vettoriali in Android prima di Lollipop e questi sono alcune delle mie librerie e versioni degli strumenti:

  • Android Studio: 2.0
  • Plugin Android Gradle: 2.0.0
  • Strumenti di compilazione: 23.0.2
  • Libreria di supporto Android: 23.3.0

Ho aggiunto questa proprietà a livello di app Build.Gradle

android {  
  defaultConfig {  
    vectorDrawables.useSupportLibrary = true  
   }  
}

Vale anche la pena ricordare che utilizzo un drawable extra come LayerDrawable (layer_list) come indicato nel blog ufficiale di Android ( link qui ) per impostare drawables per vector drawables al di fuori diapp:srcCompat

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

Troverai riferimenti diretti ai drawable vettoriali al di fuori dell'app: srcCompat fallirà prima di Lollipop. Tuttavia, AppCompat supporta il caricamento di drawable vettoriali quando vengono referenziati in un altro contenitore drawable come StateListDrawable, InsetDrawable, LayerDrawable, LevelListDrawable e RotateDrawable. Usando questo riferimento indiretto , puoi usare i drawable vettoriali in casi come l'attributo android: drawableLeft di TextView, che normalmente non sarebbe in grado di supportare i drawable vettoriali.

Quando uso app:srcCompattutto funziona bene, ma quando uso:

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

su ImageView, ImageButton, TextViewo EditTextprima di Lollipop, viene generata expection:

Caused by: android.content.res.Resources$NotFoundException: File res/drawable/search_toggle.xml from drawable resource ID #0x7f0200a9


Per vedere come utilizzare VectorDrawable con drawableLeft, drawableRight, drawableTop, drawableBottom dai un'occhiata a questa risposta
Behzad Bahmanyar

Puoi controllare la mia risposta qui? stackoverflow.com/a/40523623/2557258
Yazon2006

Nel mio caso, drawable Vactor non erano in pacchetto giusto (aperta vista del progetto) risposta originale qui stackoverflow.com/a/35836318/2163045
Murt

Risposte:


102

ULTIMO AGGIORNAMENTO - giugno / 2019

La libreria di supporto è leggermente cambiata rispetto alla risposta originale. Ora, anche il plug-in Android per Gradle è in grado di generare automaticamente il PNG in fase di compilazione. Quindi, di seguito sono riportati due nuovi approcci che dovrebbero funzionare in questi giorni. Puoi trovare maggiori informazioni qui:

Generazione PNG

Gradle può creare automaticamente immagini PNG dalle tue risorse in fase di costruzione. Tuttavia, in questo approccio, non tutti gli elementi xml sono supportati . Questa soluzione è comoda perché non è necessario modificare nulla nel codice o nel file build.gradle. Assicurati solo di utilizzare Android Plugin 1.5.0 o versioni successive e Android Studio 2.2 o versioni successive .

Sto usando questa soluzione nella mia app e funziona bene. Nessun flag build.gradle aggiuntivo necessario. Non sono necessari hack. Se vai a / build / generated / res / pngs / ... puoi vedere tutti i PNG generati.

Quindi, se hai qualche semplice icona (poiché non tutti gli elementi xml sono supportati), questa soluzione potrebbe funzionare per te. Aggiorna il tuo Android Studio e il tuo plug-in Android per Gradle.

Libreria di supporto

Probabilmente, questa è la soluzione che funzionerà per te. Se sei arrivato qui, significa che il tuo Android Studio non sta generando automaticamente i PNG. Quindi, la tua app si arresta in modo anomalo.

O forse non vuoi affatto che Android Studio generi alcun PNG.

A differenza della "generazione Auto-PNG" che supporta un sottoinsieme di elementi XML, questa soluzione supporta tutti i tag xml. Quindi, hai pieno supporto per il tuo disegno vettoriale.

Devi prima aggiornare il tuo build.gradle per supportarlo:

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
}

E poi, usa app:srcCompatinvece che android:srcdurante il caricamento VectorDrawables. Non dimenticarlo.

Perché TextView, se stai usando la androidxversione della libreria di supporto, puoi usare app:drawableLeftCompat(o destra, in alto, in basso) invece diapp:drawableLeft

In caso di CheckBox/ RadioButton, usa app:buttonCompatinvece di android:button.

Se non stai utilizzando la androidxversione della libreria di supporto e la tua minSdkVersionè 17o superiore o stai utilizzando un pulsante, puoi provare a impostare a livello di programmazione tramite

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

AGGIORNAMENTO - luglio / 2016

Hanno riattivato quel VectorDrawable nella
libreria di supporto Android 23.4.0

Per gli utenti di AppCompat , abbiamo aggiunto un'API opt-in per riattivare il supporto Vector Drawables dalle risorse (il comportamento trovato nella 23.2) tramite AppCompatDelegate.setCompatVectorFromResourcesEnabled (true) - tieni presente che questo può ancora causare problemi con l'utilizzo della memoria e problemi di aggiornamento delle istanze di configurazione, quindi perché è disabilitato per impostazione predefinita.

Forse , build.gradlel'impostazione è ormai obsoleto e basta per consentirgli di attività proprie (tuttavia, hanno bisogno di test).

Ora, per abilitarlo, devi fare:

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

    ...
}

Risposta originale - aprile 2016

Penso che ciò stia accadendo perché Support Vector è stato disabilitato nell'ultima versione della libreria: 23.3.0

Secondo questo POST :

Per gli utenti di AppCompat, abbiamo deciso di rimuovere la funzionalità che consente di utilizzare i disegni vettoriali dalle risorse sui dispositivi pre-Lollipop a causa di problemi riscontrati nell'implementazione nella versione 23.2.0 / 23.2.1 (EDIZIONE 205236) . Utilizzando app: srcCompat e setImageResource () continua a funzionare.

Se visiti il ​​problema NUMERO 205236 , sembra che verranno abilitati in futuro, ma il problema della memoria non verrà risolto presto:

Nella prossima versione ho aggiunto un'API di attivazione in cui è possibile riattivare il supporto di VectorDrawable che è stato rimosso. Viene fornito con gli stessi avvertimenti di prima (utilizzo della memoria e problemi con l'aggiornamento della configurazione).

Ho avuto un problema simile. Quindi, nel mio caso, ho ripristinato di nuovo tutte le icone che utilizzano il disegno vettoriale dalla risorsa alle immagini PNG (poiché il problema di memoria continuerà a verificarsi anche dopo che forniscono un'opzione per abilitarlo di nuovo).

Non sono sicuro che questa sia l'opzione migliore, ma a mio parere risolve tutti gli arresti anomali.


1
Grazie @Guilherme P. ma perché non hai rimosso la vectorDrawables.useSupportLibrary = trueperoperty per tornare ad abilitare la generazione di png in fase di compilazione ?
Behzad Bahmanyar

1
Questo è stato disabilitato nell'ultima versione v23.3.0 a causa di problemi di memoria. In questo modo, non possono generare png in fase di esecuzione ... Ecco perché nell'errore logcat stampano: vettore di tag sconosciuto (o qualcosa del genere).
W0rmH0le

4
Ecco le istruzioni per l' attivazione plus.google.com/+AndroidDevelopers/posts/B7QhFkWZ6YX . Purtroppo VectorDrawables non funziona ancora sul dispositivo Pre-Lollipop. Sono nella libreria di supporto 23.4.0 e ho sia "generatedDensities = []" che "vectorDrawables.useSupportLibrary = true" chiamati in defaultConfig {}.
Adam Hurwitz

1
@AdamHurwitz ho aggiornato la risposta .. Sembra che sia stato abilitato di nuovo .. Tuttavia, ora devi abilitarlo diversamente.
W0rmH0le

1
@juztcode Hai ragione. Dovresti usare "androidx.appcompat: appcompat: 1.1.0"
W0rmH0le

63

Ho avuto lo stesso problema. Ma facendo molta ricerca e sviluppo ho avuto la risposta.

Per l'uso di Imageview e ImageButton app:srcCompat="@drawable/...." e per altre visualizzazioni come Button, Textview, invece di utilizzare "drawableLeft/right..."nell'XML, specificare i drawables programmaticamente come:

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

E usa "AppCompatResources" per ottenere il drawable.



39

La risposta di Guillherme P è davvero fantastica. Solo per fare un piccolo miglioramento, non è necessario aggiungere quella riga in ogni attività, se l'hai aggiunta una volta nella classe Application funzionerà anche.

public class App extends Application {

static {
    AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
}

RICORDA: Devi ancora aver abilitato l'uso della libreria di supporto in gradle:

android {
  defaultConfig {
    vectorDrawables.useSupportLibrary = true
  }
}

Inoltre, assicurati di utilizzare una versione della libreria di supporto superiore alla v23.4, quando Google ha aggiunto di nuovo il supporto per Drawable Containers per VectorDrawables ( nota di rilascio )

Aggiornare

E per le modifiche al codice:

  1. Assicurati di aggiornare a app:srcCompatogni posto che accetta l' android:srcattributo (l'IDE ti avviserà se non è valido come per il <bitmap>tag).
  2. Per drawableLeft, drawableStart, drawableRight, drawableEndattributi utilizzati in TextViewe opinioni simili, si dovrà impostare loro programmazione per ora. Un esempio di impostazione 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);
    }
    

ricorda che devi avere ON l'uso della libreria di supporto per i drawables vettoriali in gradle: vectorDrawables.useSupportLibrary = true
Benny

2
Sì. Lo so. Ma è necessario un wrapper per far funzionare i drawable vettoriali come drawable per TexViews, quindi questa risposta è incompleta.
cesards

1
Bella risposta. È particolarmente utile per le app con tutte le sue attività estese da un'attività di base personalizzata.
Hong

14

Ho avuto lo stesso problema. E risolvilo rimuovendo

vectorDrawables.useSupportLibrary = true

La mia versione di destinazione è 25 e la libreria di supporto è

 compile 'com.android.support:appcompat-v7:25.3.1'

1
questo ha funzionato per me. Grazie. L'ho appena rimossovectorDrawables.useSupportLibrary = true
Android Mediocre

Penso che questo non sia il modo corretto per farlo, in ogni caso ho rinunciato alla tua risposta. !!
Harish Reddy

Grazie. t funziona per la mia app. Tutti i disegnabili vettoriali funzionano ancora se sono stati rimossi. L'app utilizza com.android.support:appcompat-v7:28.0.0
Hong

10

VectorDrawables su pre-lollipop dovrebbe funzionare bene senza usare

AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);

Se vuoi usare VectorDrawables all'interno di ImageViews, puoi usare l'attributo srcCompate funzionerà, ma all'interno di Buttons o TextViews no , quindi devi avvolgere il Drawable in un InsetDrawable o in un LayerDrawable. C'è un altro trucco che ho scoperto, se stai usando il data binding, potresti farlo:

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

Magicamente funzionerà, non ho indagato su cosa sta succedendo dietro le quinte, ma immagino che TextView utilizzi il metodo getDrawable da AppCompatResources o simili.


Come impostare l'immagine vettoriale nel selettore?
Tushar Gogna

dopo aver impostato vectorDrawables.useSupportLibrary = true in gradle default e AppCompatDelegate.setCompatVectorFromResourcesEnabled (true); in attività alla creazione Per evitare crash con Android: drawableleft in Textview , imposta drawble left sulla textview in modo programmatico per esempio: textview.setCompoundDrawablesWithIntrinsicBounds (R.drawable.movie, 0, 0, 0);
Afjalur Rahman Rana

7

Un sacco di ricerca e sviluppo, finalmente ottenendo questa soluzione per i crash sui dispositivi pre-lollipop.

Per Imageview

  • usa app: srcCompat invece di android: src

Per TextView / EditText

  • Rimuovi drawableleft , drawableright .... e imposta dal codice java disegnabile.

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

Per Build.gradle

vectorDrawables.useSupportLibrary = true


1
Era l'unica soluzione che funzionava su TextInputEditText.
heronsanches

1
Stupendo, questo è stato risolto il mio problema. Questa dovrebbe essere una risposta accettata.
DJtiwari

6

Modo più semplice da usare:

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

e ... app:**Compatusalo solo per compatibilità. Aggiungi anche supporto su build.gradle(modulo)

android {
   defaultConfig {
       vectorDrawables.useSupportLibrary = true
   }
}

app: drawableEndCompat e app: drawableRightCompat sono praticamente la stessa cosa se è inglese
Hossam Hassan

5

Per chiunque esegua l'aggiornamento ad Android Gradle 3.0 e versioni successive, non è necessario utilizzare AppCompatDelegate.setCompatVectorFromResourcesEnabled(true)o impostare vectorDrawables.useSupportLibrary = true(aggiungere questo causerà problemi) e utilizzare app:srcCompat, funziona e basta.

Mi ci vogliono due giorni per capirlo e non ho trovato alcun documento correlato nei documenti di Google ...


Interessante, sto usando gradle 3.3.0 e questa soluzione funziona. Tuttavia, Android Studio mi sta ancora dicendo di abilitare set vectorDrawables.useSupportLibrary = true.
masterwok

2

Sto usando VectorDrawables su dispositivi Pre-lollipop ed è così che lo faccio: -

Passaggio 1: inseriscilo nel gradle a livello di app.

android {
  defaultConfig {
    vectorDrawables.useSupportLibrary = true
  }
}

Passo 2:

Inseriscilo nella tua classe Application e non dimenticare di registrare la tua classe Application nel file manifest.

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

Passaggio 3:

Ottieni VectorDrawables usando,

imageView.setImageDrawable(ContextCompat.getDrawable(this, R.drawable.my_vector_drawable));

2

Dopo aver utilizzato il codice seguente.

android {
  defaultConfig {
  vectorDrawables.useSupportLibrary = true  
                }
        }




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

tuttavia, esiste un problema con le immagini vettoriali per gli attributi di seguito

DrawableEnd, DrawableStart, DrawableTop, DrawableBottom, Background

In questo caso, seguire come di seguito, invece di fare riferimento direttamente all'immagine vettoriale, utilizzare il tag selector come file disegnabile intermedio.

Esempio:

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>

Il tuo TextView / 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"
       />

Grazie !!! Per la proprietà dello sfondo, l'aggiunta di un selettore in mezzo piuttosto che usare direttamente il disegno vettoriale ha funzionato per l'api pre-lecca-lecca (19).
Ankur

nel mio caso, questo ancora non funziona per API (16), anche avvolgendo conselector
mochadwi

1

Abbiamo provato 3 cose

vectorDrawables.useSupportLibrary = true

Impostazione di setCompatVectorFromResourcesEnabled nella classe Application

static {
    AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
}

E usa app:srcCompat

Ma anche dopo che stava fallendo

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

poi abbiamo scoperto che il nostro SVG aveva un tag Gradient. La conversione del tag gradiente in percorsi individuali per le API inferiori <= 23 e l'utilizzo della stessa API SVG> = 24 ha funzionato.

Ho ricevuto aiuto da questa risposta https://stackoverflow.com/a/47783962/2171513


Non so perché nessuno lo voti, ma questa potrebbe effettivamente essere la soluzione al mio problema. Grazie
DevMike01

0

Sovrapponi semplicemente il vettore tracciabile alla lista di stato, quindi il problema sarà risolto

Ad esempio, hai un'immagine vettoriale freccia indietro:

ic_back_arrow.xml

sì, dovresti sovrapporlo alla lista dei livelli xml (ic_back_arrow_vector_vector.xml):

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

Perché la logica:

vectorDrawables.useSupportLibrary = true

e

AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);

non ti aiuterà su alcuni dispositivi cinesi e dispositivi Samsung meno recenti. Se non li sovrapponi, fallirà.


0

Ho lottato con questo per ore.

Ho provato tutto ciò che queste risposte mi hanno detto, ma la mia app non ha smesso di bloccarsi. Ho cancellato questa riga: app:srcCompat="@drawable/keyboard"e la mia app ha smesso di bloccarsi. e poi quando ho aggiunto di nuovo la stessa cosa, ha iniziato a bloccarsi di nuovo. Quindi ho deciso di aprire quel file e ho visto un errore nella prima riga che diceva

"La 'Tastiera' disegnabile non ha alcuna dichiarazione nella cartella drawable di base; questo può portare a crash.

Ho fatto clic con il pulsante destro del mouse sul file e ho fatto clic su "Mostra in explorer" e non era nella cartella drawable ma nella directory drawable-v24. Così l'ho copiato e incollato nella directory disegnabile e finalmente mi sono sbarazzato dei crash.


-2

Il suggerimento di Guilherme P non funzionava per me. Sono andato avanti e ho preso la decisione di utilizzare png dove devo fare cose al di fuori dell'app: srcCompat cioè drawableLeft, drawableRight, ecc. Questa è stata una modifica abbastanza semplice da apportare e non ha i potenziali problemi di memoria AppCompatDelegate.setCompatVectorFromResourcesEnabled ( vero); introduce.


-3

Un'alternativa alla risposta di Benny è creare una Activitysuperclasse:

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

  //...
}

Ora estendi VectorDrawableActivityinvece di AppCompatActivity.


@cesards Perché no?
Code-Apprentice
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.