45

Sono di fronte a un problema con la nuova compatibilità con VectorDrawables. Nella libreria di supporto 23.2 è stata introdotta una nuova funzionalità per la compatibilità con le versioni precedenti di VectorDrawables Android.Selettore Android disegnato con VectorDrawables srcCompat

Ho un ImageView a cui è assegnato un SelectorDrawable. Questo Drawable contiene diversi VectorDrawables, quindi ho pensato che dovrei usare app: srcCompat per la compatibilità. Ma non funziona sul mio Galaxy S2 con 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> 

Tutti i drawable sono file vettoriali xml.

Quando si utilizza questa SelectorDrawable con srcCompat ottengo questo errore:

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 

utilizzando Android: src è ancora peggio.

Se utilizzo uno dei drawable vettoriali con app: srcCompat funziona correttamente. Quindi immagino sia un problema con SelectorDrawable e compatibilità.

Qualcuno ha avuto lo stesso problema e ha trovato una soluzione oppure non è attualmente possibile utilizzare VectorDrawables in SelectorDrawables prima di Android 5?

I fatti in breve:

  • Compile target API 23
  • Supporto Libraray 23.3.0
  • vectorDrawables.useSupportLibrary = true
  • Gradle 2,0
+1

Supporto per il caricamento di vettore drawable dalle risorse è stato rimosso nella versione 23.3 - https://plus.google.com/+AndroidDevelopers/posts/iTDmFiGrVne – Jahnold

+1

Ma: "Uso di app: srcCompat e setImageResource() continua a funzionare "così app: srcCompat dovrebbe funzionare ancora in 23.3. o no? – marilion91

+2

Sì utilizzando app: srcCompat funziona ancora in modo da poter impostare un VectorDrawable su un ImageView. Tuttavia, il caricamento dei drawable in un elenco di stati xml non funziona più purtroppo – Jahnold

risposta

50

alcune cose sono cambiate da quando ho fatto questa domanda, quindi risponderò io stesso.

Con libreria di supporto 23.4.0 il supporto per VectorDrawables da Ressources è stato riattivato: Android Support Library 23.4.0 available now

Potete trovare ulteriori informazioni su che in questo cast del Google I/O 2016: What's new in the support library - Google I/O 2016

È necessario per aggiungere questo ad ogni attività in cui si desidera utilizzare VectorDrawables su dispositivi sotto Android 5.0 (nome in codice Lollipop, livello di API 21):

static { 
    AppCompatDelegate.setCompatVectorFromResourcesEnabled(true); 
} 

Così ora è possibile usa VectorDrawables in DrawableContainer ma può comunque causare alcuni problemi come menzionato nelle fonti precedenti, quindi usalo con cautela.

Non ho riabilitato questa funzione nella mia app finora, ma cambierò molte delle mie icone in VectorDrawables con la mia prossima major release e quindi approfondirò questo argomento.

+0

Inoltre, il seguente bug report potrebbe essere d'aiuto: https://code.google.com/p/android/issues/detail?id = 210745 & pageId = 109201119303080409719 –

+0

"È necessario aggiungere questo ad ogni attività in cui si desidera utilizzare VectorDrawables sui dispositivi sotto Android 5" non è vero, ne abbiamo bisogno anche per Android 15 – stallianz

+8

@stallianz Android 5 è uguale a livello di API 21. Non confondere le versioni di rilascio con le versioni API. – F43nd1r

33

Come menzionato in @Jahnold il commento alla domanda, il supporto per il caricamento del vettore drawable da una lista xml di stato xml è stato rimosso in 23.3.

Tuttavia, ho trovato diversi approcci che possono aiutare.

1. Uso Tint

L'approccio è adatto se i drawable dalla differenza elenco stato selezionato da colori.

In primo luogo, creare un solo drawable vettore con tinta e nero 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> 

In secondo luogo, creare il colore elenco stato button_tint.xml posto 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> 

Non dimenticate di aggiungere linee da seguire per build.gradle oppure l'approccio non funzionerà con le vecchie versioni di Android.

defaultConfig { 
    vectorDrawables.useSupportLibrary = true 
} 

2. hardcode creando StateListDrawable

L'approccio è adatto se si utilizza per la lista di stato drawable vettoriale che differenza non è solo un colore, ma anche da una figura quindi è necessario creare più file XML diversi .Quindi è possibile creare StateListDrawable a livello di programmazione come mostrato in un answer.

+5

Trascorro un'ora per scoprire che il file 'button_tint.xml' deve essere posizionato nella cartella'/res/color'. Quindi, non dimenticarlo. –

+0

Probabilmente non dovresti definire la modalità tinta e tinta nel drawable stesso. Questo limita la riutilizzabilità dei drawable. Se il progettista decide di cambiare il colore, o ha la stessa icona ma in colori diversi, è necessario duplicare il drawable invece di limitarsi a colorare usando uno stile ecc. –

+0

@Ghristopher Perry In questo caso puoi usare il secondo approccio. –

4

Dopo aver visto Novità nella libreria di supporto - Google I/O 2016 Ho notato un metodo utile nella classe AppCompatResources. Questo è AppCompatResources#getColorStateList(Context context, int resId). Con l'aiuto di questo metodo ho implementato il selettore con i drawable vettoriali. Qui è il mio colore di file di selezione 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> 

E c'è metodo Java che restituisce colorata drawable:

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

è possibile utilizzarlo come indicato qui sotto

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

Lavorare bene con sottostante i cambiamenti.

static { 
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true); 
} 

Aggiunto in Classe di applicazione.
app build.gradle all'interno defaultconfig

vectorDrawables.useSupportLibrary = true