Usando drawables vetoriais de Android na falha anterior ao Lollipop

91

Estou usando drawables vetoriais no Android antes do Lollipop e estes são algumas das minhas bibliotecas e versões de ferramentas:

  • Android Studio: 2.0
  • Plug-in do Android para Gradle: 2.0.0
  • Ferramentas de construção: 23.0.2
  • Biblioteca de Suporte Android: 23.3.0

Eu adicionei esta propriedade no meu nível de aplicativo Build.Gradle

android {  
  defaultConfig {  
    vectorDrawables.useSupportLibrary = true  
   }  
}

Também vale a pena mencionar que eu uso um drawable extra, como LayerDrawable (layer_list), conforme declarado no Blog oficial do Android ( link aqui ) para definir drawables para drawables vetoriais fora deapp:srcCompat

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

Você encontrará drawables vetoriais que fazem referência direta fora do app: srcCompat falhará antes do Lollipop. No entanto, AppCompat oferece suporte ao carregamento de drawables vetoriais quando eles são referenciados em outro contêiner de drawable, como StateListDrawable, InsetDrawable, LayerDrawable, LevelListDrawable e RotateDrawable. Usando essa indireção , você pode usar drawables vetoriais em casos como o atributo android: drawableLeft do TextView, que normalmente não seria capaz de suportar drawables vetoriais.

Quando estou usando app:srcCompattudo funciona bem, mas quando eu uso:

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

em ImageView, ImageButton, TextViewou EditTextantes do Lollipop, ele lança uma expection:

Caused by: android.content.res.Resources$NotFoundException: File res/drawable/search_toggle.xml from drawable resource ID #0x7f0200a9
Behzad Bahmanyar
fonte
Possível duplicata de compatibilidade de vetores Android
Adam Hurwitz
Para ver como usar VectorDrawable com drawableLeft, drawableRight, drawableTop, drawableBottom, verifique Esta resposta
Behzad Bahmanyar
Você pode verificar minha resposta aqui? stackoverflow.com/a/40523623/2557258
Yazon2006
No meu caso, drawables de vactor não estavam no pacote certo (visualização aberta do projeto) resposta original aqui stackoverflow.com/a/35836318/2163045
murt

Respostas:

102

ÚLTIMA ATUALIZAÇÃO - Jun / 2019

A Biblioteca de Suporte mudou um pouco desde a resposta original. Agora, até mesmo o plug-in do Android para Gradle é capaz de gerar automaticamente o PNG no momento da construção. Portanto, a seguir estão duas novas abordagens que devem funcionar atualmente. Você pode encontrar mais informações aqui:

Geração PNG

O Gradle pode criar automaticamente imagens PNG de seus ativos no momento da construção. No entanto, nesta abordagem, nem todos os elementos xml são suportados . Esta solução é conveniente porque você não precisa alterar nada em seu código ou em seu build.gradle. Certifique-se de usar o Android Plugin 1.5.0 ou superior e o Android Studio 2.2 ou superior .

Estou usando essa solução no meu aplicativo e funciona bem. Nenhum sinalizador build.gradle adicional necessário. Nenhum hacks é necessário. Se você acessar / build / generated / res / pngs / ... poderá ver todos os PNGs gerados.

Portanto, se você tiver algum ícone simples (uma vez que nem todos os elementos xml são suportados), esta solução pode funcionar para você. Basta atualizar o Android Studio e o plug-in do Android para Gradle.

Biblioteca de Apoio

Provavelmente, esta é a solução que funcionará para você. Se você veio aqui, significa que o Android Studio não está gerando os PNGs automaticamente. Então, seu aplicativo está travando.

Ou talvez você não queira que o Android Studio gere nenhum PNG.

Diferentemente daquela "geração Auto-PNG" que suporta um subconjunto de elementos XML, esta solução suporta todas as tags xml. Portanto, você tem suporte total para seu drawable vetorial.

Você deve primeiro atualizar seu build.gradle para suportá-lo:

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 então, use em app:srcCompatvez de android:srcdurante o carregamento VectorDrawables. Não se esqueça disso.

Pois TextView, se você estiver usando a androidxversão da Biblioteca de Suporte, você pode usar app:drawableLeftCompat(ou direita, parte superior, parte inferior) em vez deapp:drawableLeft

No caso de CheckBox/ RadioButton, use em app:buttonCompatvez de android:button.

Se você não estiver usando a androidxversão da Biblioteca de Suporte e sua minSdkVersioné 17ou superior ou usando um botão, você pode tentar definir programaticamente via

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

ATUALIZAÇÃO - Jul / 2016

Eles reativaram o VectorDrawable na
Android Support Library 23.4.0

Para usuários AppCompat , nós adicionamos um opt-in API para reativar Support Vector Drawables de recursos (o comportamento encontrado em 23,2) via AppCompatDelegate.setCompatVectorFromResourcesEnabled (true) - mantenha em mente que este ainda pode causar problemas com o uso de memória e problemas ao atualizar instâncias de configuração, por isso é desabilitado por padrão.

Talvez , build.gradleconfiguração é agora obsoleto e você só precisa habilitá-lo em atividades próprias (no entanto, necessidade de testar).

Agora, para habilitá-lo, você deve fazer:

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

    ...
}

Resposta Original - Abr / 2016

Acho que isso está acontecendo porque o Support Vector foi desativado na última versão da biblioteca: 23.3.0

De acordo com este POST :

Para usuários do AppCompat, decidimos remover a funcionalidade que permite usar drawables vetoriais de recursos em dispositivos pré-Lollipop devido a problemas encontrados na implementação na versão 23.2.0 / 23.2.1 (ISSUE 205236) . O uso de app: srcCompat e setImageResource () continua a funcionar.

Se você visitar o problema ISSUE 205236 , parece que eles serão ativados no futuro, mas o problema de memória não será corrigido em breve:

Na próxima versão, adicionei uma API opcional onde você pode reativar o suporte VectorDrawable que foi removido. Ele vem com as mesmas ressalvas de antes (uso de memória e problemas com a atualização da configuração).

Eu tive uma questão semelhante. Portanto, no meu caso, reverti todos os ícones que usam drawable vetorial de recursos para imagens PNG novamente (já que o problema de memória continuará acontecendo mesmo depois de fornecerem uma opção para ativá-lo novamente).

Não tenho certeza se esta é a melhor opção, mas corrige todas as falhas na minha opinião.

W0rmH0le
fonte
1
Obrigado @Guilherme P., mas por que você não removeu a vectorDrawables.useSupportLibrary = trueperoperty para voltar a habilitar a geração de PNGs no tempo de compilação novamente?
Behzad Bahmanyar
1
Isso foi desativado na versão mais recente v23.3.0 devido a problemas de memória. Dessa forma, eles não podem gerar png em tempo de execução ... É por isso que no erro do logcat eles imprimem: vetor de tag desconhecido (ou algo parecido).
W0rmH0le
4
Aqui estão as instruções de ativação plus.google.com/+AndroidDevelopers/posts/B7QhFkWZ6YX . Infelizmente, o VectorDrawables ainda não está funcionando no dispositivo Pré-Lollipop. Estou na Biblioteca de Suporte 23.4.0 e tenho 'generatedDensities = []' e 'vectorDrawables.useSupportLibrary = true' chamados em defaultConfig {}.
Adam Hurwitz
1
@AdamHurwitz Atualizei a resposta .. Parece que foi habilitado novamente .. No entanto, você deve habilitá-lo de forma diferente agora.
W0rmH0le
1
@juztcode Você está certo. Você deve usar 'androidx.appcompat: appcompat: 1.1.0'
W0rmH0le
63

Eu tive o mesmo problema. Mas fazendo muito P&D, obtive a resposta.

Para uso de Imageview e ImageButton, app:srcCompat="@drawable/...." e para outras visualizações como Button, Textview, em vez de usar "drawableLeft/right..."no XML, especifique drawables programaticamente como:

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

E use "AppCompatResources" para obter o drawable.

Shashank Kapsime
fonte
59

Para elaborar outras respostas muito boas , aqui está um diagrama que pode ajudá-lo. É válido se você tiver Biblioteca de Suporte de 23.4.0 a pelo menos 25.1.0.

Cheatsheet VectorDrawable

David Ferrand
fonte
1
caso você esteja tentando definir drawableLeft, envolva-o dentro de um drawable como mencionado aqui. medium.com/@chrisbanes/…
nizam.sp
Obrigado este gráfico nos ajuda muito.
silentsudo,
39

A resposta de Guillherme P é incrível. Apenas para fazer uma pequena melhoria, você não precisa adicionar essa linha em todas as atividades, se você a adicionou uma vez na classe Application, ela também funcionará.

public class App extends Application {

static {
    AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
}

LEMBRE-SE: você ainda precisa ter ativado o uso da biblioteca de suporte no gradle:

android {
  defaultConfig {
    vectorDrawables.useSupportLibrary = true
  }
}

Além disso, certifique-se de usar uma versão da biblioteca de suporte superior a v23.4, quando o Google adicionou de volta o suporte para Drawable Containers para VectorDrawables ( nota de lançamento )

Atualizar

E para alterações de código:

  1. Certifique-se de atualizar para app:srcCompatcada local que aceita o android:srcatributo (o IDE irá avisá-lo se for inválido como para a <bitmap>tag).
  2. Por drawableLeft, drawableStart, drawableRight, drawableEndatributos usados em TextViewe opiniões semelhantes, você terá que configurá-los por meio de programação para agora. Um exemplo de configuração 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
fonte
lembre-se de que você precisa ativar o uso da biblioteca de suporte para drawables vetoriais no gradle: vectorDrawables.useSupportLibrary = true
Benny
2
Sim. Eu sei. Mas é necessário um wrapper para fazer drawables vetoriais funcionarem como drawables para TexViews, então esta resposta está incompleta.
cesards
1
Ótima resposta. É particularmente bom para aplicativos com todas as suas atividades estendidas de uma atividade base personalizada.
Hong,
14

Eu tive o mesmo problema. E conserte removendo

vectorDrawables.useSupportLibrary = true

Minha versão alvo é 25 e a biblioteca de suporte é

 compile 'com.android.support:appcompat-v7:25.3.1'
Rajesh Nasit
fonte
1
isso funcionou para mim. Obrigado. Acabei de remover issovectorDrawables.useSupportLibrary = true
Android Mediocre de
Acho que essa não é a maneira correta de fazer isso, De qualquer forma, desisti de votar na sua resposta. !!
Harish Reddy
Obrigado. t funciona para meu aplicativo. Todos os drawables vetoriais ainda funcionam se tiverem sido removidos. O aplicativo usa com.android.support:appcompat-v7:28.0.0
Hong
10

VectorDrawables no pré-pirulito deve funcionar bem sem usar

AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);

Se você quiser usar VectorDrawables dentro de ImageViews, você pode usar o atributo srcCompate ele funcionará, mas dentro de Buttons ou TextViews não funcionará , então você precisa envolver o Drawable em um InsetDrawable ou um LayerDrawable. Há outro truque que descobri: se você estiver usando vinculação de dados, poderá fazer isso:

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

Isso funcionará magicamente, não investiguei o que está acontecendo nos bastidores, mas acho que TextView está usando o método getDrawable do AppCompatResources ou similar.

cesards
fonte
Como definir a imagem vetorial no seletor?
Tushar Gogna
após definir vectorDrawables.useSupportLibrary = true no gradle default e AppCompatDelegate.setCompatVectorFromResourcesEnabled (true); em atividade na criação Para evitar travar com o android: drawableleft no Textview , defina o drawble à esquerda para textview programaticamente, por exemplo: textview.setCompoundDrawablesWithIntrinsicBounds (R.drawable.movie, 0, 0, 0);
Afjalur Rahman Rana
7

Muito P&D, finalmente obtendo esta solução para travamentos em dispositivos pré-pirulito.

Para Imageview

  • use app: srcCompat em vez de android: src

Para TextView / EditText

  • Remova drawableleft , drawableright .... e defina a partir do código java drawable.

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

Para Build.gradle

vectorDrawables.useSupportLibrary = true

Jatin Mandanka
fonte
1
Foi a solução única que funcionou no TextInputEditText.
heronsanches
1
Awsome, isso está resolvido meu problema. Esta resposta deve ser aceita.
DJtiwari
6

Maneira mais fácil de usar:

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

e ... use apenas app:**Compatpara compatibilidade. Também adicione suporte em build.gradle(módulo)

android {
   defaultConfig {
       vectorDrawables.useSupportLibrary = true
   }
}
Hamed Jaliliani
fonte
app: drawableEndCompat e app: drawableRightCompat são praticamente a mesma coisa se for inglês
Hossam Hassan
5

Para quem atualizar para o Android Gradle 3.0 e superior, não há necessidade de usar AppCompatDelegate.setCompatVectorFromResourcesEnabled(true), ou definir vectorDrawables.useSupportLibrary = true(adicionar isso causará problema) e usar app:srcCompat, ele simplesmente funciona.

Levei dois dias para descobrir isso e não encontrei nenhum documento relacionado nos documentos do Google ...

Geng Jiawen
fonte
Interessante, estou usando o gradle 3.3.0 e essa solução funciona. No entanto, o Android Studio ainda está me dizendo para habilitar set vectorDrawables.useSupportLibrary = true.
masterwok
2

Estou usando VectorDrawables em dispositivos pré-pirulito e é assim que faço: -

Etapa 1: coloque isso em seu gradle de nível de aplicativo.

android {
  defaultConfig {
    vectorDrawables.useSupportLibrary = true
  }
}

Passo 2:

Coloque isso em sua classe Application e não se esqueça de registrar sua classe Application no arquivo de manifesto.

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

Etapa 3:

Obtenha o VectorDrawables usando,

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

Depois de usar o código abaixo.

android {
  defaultConfig {
  vectorDrawables.useSupportLibrary = true  
                }
        }




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

ainda assim, existe um problema de imagens vetoriais para os atributos abaixo

DrawableEnd, DrawableStart, DrawableTop, DrawableBottom, Background

Nesse caso, siga as instruções abaixo. Em vez de fazer referência à imagem vetorial diretamente, use a marca do seletor como um arquivo drawable intermediário.

Exemplo:

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>

Seu 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"
       />
Rajesh Gr
fonte
Obrigado !!! Para a propriedade de fundo, adicionar o seletor no meio em vez de usar diretamente o drawable vetorial funcionou para a API pré-pirulito (19).
Ankur
no meu caso, isso ainda não funciona para API (16), mesmo envolvendo comselector
mochadwi
1

Nós tentamos 3 coisas

vectorDrawables.useSupportLibrary = true

Configurando setCompatVectorFromResourcesEnabled na classe Application

static {
    AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
}

E use app:srcCompat

Mas mesmo depois disso, estava falhando com

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

então descobrimos que nosso SVG tinha uma tag Gradient. Converter a tag gradiente em caminhos individuais para a API inferior <= 23 e usar a mesma API SVG> = 24 funcionou.

Obteve ajuda com esta resposta https://stackoverflow.com/a/47783962/2171513

Aalap
fonte
Não sei por que ninguém aprovou isso, mas essa poderia ser a solução para o meu problema. Obrigado
DevMike01
0

Simplesmente sobreponha o drawable vetorial à lista de estados, então o problema será resolvido

Por exemplo, você tem uma imagem vetorial de seta para trás:

ic_back_arrow.xml

sim, você deve sobrepô-lo à lista de camadas 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>

Porque a lógica:

vectorDrawables.useSupportLibrary = true

e

AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);

não irá ajudá-lo em alguns dispositivos da China e dispositivos Samsung mais antigos. Se você não os sobrepuser, ele falhará.

sr.boyfox
fonte
0

Eu estava lutando com isso por horas.

Tentei tudo o que essas respostas me disseram, mas meu aplicativo não parou de travar. Excluí esta linha: app:srcCompat="@drawable/keyboard"e meu aplicativo parou de travar. e então, quando adicionei a mesma coisa de volta, ele começou a travar novamente. Decidi abrir esse arquivo e vi um erro na primeira linha dizendo

"O drawable 'Keyboard' não tem declaração na pasta de drawable base; isso pode causar travamentos.

Cliquei com o botão direito no arquivo e cliquei em "Mostrar no explorer" e não estava na pasta drawable, mas no diretório drawable-v24. Então eu copiei e colei no diretório drawable e finalmente me livrei das falhas.

Fahad Maqsood Qazi
fonte
-2

A sugestão do Guilherme P não estava funcionando para mim. Fui em frente e tomei a decisão de usar png onde preciso fazer coisas fora do app: srcCompat, ou seja, drawableLeft, drawableRight, etc. Essa foi uma alteração muito fácil de fazer e não tem os possíveis problemas de memória AppCompatDelegate.setCompatVectorFromResourcesEnabled ( verdade); apresenta.

Ryan Newsom
fonte
-3

Uma alternativa para a resposta de Benny é criar uma Activitysuperclasse:

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

  //...
}

Agora estenda em VectorDrawableActivityvez de AppCompatActivity.

Code-Apprentice
fonte
@cesards Por que não?
Code-Apprentice