Como referenciar atributos de estilo de um drawable?


96

Quero ter 2 temas selecionáveis ​​para meu aplicativo. Para fazer isso, defini alguns atributos, como este:

 <attr format="color" name="item_background" />

Então, criei os dois temas, assim:

  <style name="ThemeA">
     <item name="item_background">#123456</item>
 </style>

 <style name="ThemeB">
     <item name="item_background">#ABCDEF</item>
 </style>

Este método funciona muito bem, permitindo-me criar e modificar vários temas facilmente. O problema é que parece que só pode ser usado em Views, e não em Drawables .

Por exemplo, fazer referência a um valor de uma Visualização dentro de um layout funciona:

 <TextView android:background="?item_background" />

Mas fazer o mesmo em um Drawable não:

 <shape android:shape="rectangle">
     <solid android:color="?item_background" />
 </shape>

Recebo este erro ao executar o aplicativo:

    java.lang.UnsupportedOperationException: Can't convert to color: type=0x2

Se em vez de ?item_backgroundusar uma cor codificada, funciona, mas isso não me permite usar meus temas. Eu também tentei ?attr:item_background, mas acontece o mesmo.

Como posso fazer isso? E por que funciona em visualizações, mas não em Drawables? Não consigo encontrar essa limitação em nenhum lugar da documentação ...


Pode ser uma duplicata da seguinte pergunta: stackoverflow.com/questions/7529574/…
Paul Lammertsma

@Martin M., o que você descobriu com isso?
user123321

Alguma solução para isso ainda? Estou atingindo exatamente a mesma parede
Guillaume

Outra questão mais recente aqui: stackoverflow.com/q/12115125/317889 Mesmo problema. Classifique Google.
HGPB

3
Aparentemente, esse problema foi resolvido na visualização do Android L, conforme especificado aqui: code.google.com/p/android/issues/detail?id=26251
Bianca Daniciuc

Respostas:


161

Em minha experiência, não é possível fazer referência a um atributo em um drawable XML.
Para criar seu tema, você precisa:

  • Crie um drawable XML por tema.
  • Inclua a cor necessária em seu drawable diretamente com a @colortag ou formato #RGB.

Crie um atributo para seu drawable em attrs.xml .

<?xml version="1.0" encoding="utf-8"?>
<resources>
   <!-- Attributes must be lowercase as we want to use them for drawables -->
   <attr name="my_drawable" format="reference" />
</resources>

Adicione seu drawable ao seu theme.xml .

<style name="MyTheme" parent="@android:style/Theme.NoTitleBar">
   <item name="my_drawable">@drawable/my_drawable</item>
</style>

Referencie seu drawable em seu layout usando seu atributo.

<TextView android:background="?my_drawable" />

20
Parece que, esta solução ainda é necessária se você quiser manter a compatibilidade ... Sim, a partir de L é corrigido e a cor do tema é bem referenciada, mas o mesmo código é executado em diferentes dispositivos pré-L e na verdade a referência de atr não funciona dispositivos pré-L! LoL .. Então, para mim, não é fixo se eu tenho que manter drawables diferentes de qualquer maneira.
Davideas

2
Eu gostaria de poder votar a favor duas vezes. Apenas tentei otimizar minhas formas para usar referências em vez de #RGB codificado e obtive o mesmo erro. Procurei o SO por uma solução e encontrei a mesma resposta que votei a favor 2 semanas atrás! (facepalm)
Tiksi,

2
Isso é super ninja!
MariusBudin de

4
ARGH! Essa deve ser a principal prioridade do Google para corrigir o backport! A notação de referência é tão extremamente útil e importante que é quase impossível viver sem ela se você tiver vários temas dentro de um aplicativo. No momento, preciso fazer três XMLs drawable para cada tipo de botão personalizado!
Stephan Henningsen

2
Isso eu quero. solução muito simples e agradável em <21 SDK.
Adnan Abdollah Zaki

20

Começando com lollipop(API 21), este recurso é compatível, consulte https://code.google.com/p/android/issues/detail?id=26251

No entanto, se você está almejando dispositivos sem pirulito, não o use, pois pode travar, use a solução alternativa na resposta aceita.


Existe alguma chance de usar algum tipo de biblioteca de suporte para fazê-lo funcionar em APIs pré-L?
Ivan,

2
Não, a biblioteca de suporte é um conjunto de APIs que podem ser usados ​​em dispositivos mais antigos, essa mudança de comportamento está nas ferramentas de compilação e compilação, portanto não está relacionada à biblioteca de suporte.
marmor 01 de

3
Não, no lollipop não era um recurso implementado, mas uma correção de bug gritante. E um bug sério nisso.
Adrian Sicaru

droga, eu pensei que tinha uma boa solução de tema. agora eu tenho que voltar e criar um monte de drawables seletores de botão.
filthy_wizard

4

Embora não seja possível fazer referência a atributos de estilo de drawables em dispositivos pré-Lollipop , é possível para listas de estados de cores. Você pode usar o método AppCompatResources.getColorStateList (Context context, int resId) da Android Support Library. A desvantagem é que você terá que definir essas listas de estados de cores programaticamente.

Aqui está um exemplo muito básico.

color / my_color_state.xml

<selector xmlns:android="http://schemas.android.com/apk/res/android">
  <item android:state_checked="true" android:color="?colorControlActivated" />
  <item android:color="?colorControlNormal" />
</selector>

Um widget que precisa de uma lista de estados de cores:

<RadioButton
  android:id="@+id/radio_button"
  android:text="My Radio" />

E o mais importante:

ColorStateList csl = AppCompatResources.getColorStateList(context, R.color.my_color_state);    
RadioButton r = (RadioButton) findViewById(R.id.radio_button);
r.setTextColor(csl);

Bem, não é o caminho mais elegante ou mais curto, mas é isso que a Android Support Library faz para funcionar em versões mais antigas (pré-Lollipop) do Android.

Infelizmente, o método semelhante para drawables não funciona com atributos de estilo.


1

Respondi à mesma pergunta em https://stackoverflow.com/a/59467269/3841352, mas também a postarei aqui:

Eu encontrei o mesmo problema e desde 2019 não foi resolvido, então você não pode ter um atributo referenciado em um seletor como um drawable. Vou compartilhar a solução que obtive para o problema, pois não a vejo postada aqui. Eu encontrei no último comentário do relatório de bug .

A solução alternativa é basicamente criar um recurso drawable que será aquele que fará referência ao valor do atributo.

Para ilustrar seu caso, a solução seria em vez de:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="?attr/colorPrimary" android:state_enabled="true" android:state_window_focused="false"/>
    <item android:drawable="?attr/colorPrimaryDark" android:state_pressed="true"/>
    <item android:drawable="@android:color/darker_gray" android:state_enabled="false"/>
    <item android:drawable="?attr/colorPrimary"/>
</selector>

você substituiria? attr / * por um recurso drawable:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/colorPrimaryDrawable" android:state_enabled="true" android:state_window_focused="false"/>
    <item android:drawable="@drawable/colorPrimaryDarkDrawable" android:state_pressed="true"/>
    <item android:drawable="@android:color/darker_gray" android:state_enabled="false"/>
    <item android:drawable="@drawable/colorPrimaryDrawable"/>
</selector>

Os drawables seriam definidos como:

drawable / colorPrimaryDrawable

<shape xmlns:android="http://schemas.android.com/apk/res/android"android:shape="rectangle">
    <solid android:color="?attr/colorPrimary" />
</shape>

drawable / colorPrimaryDarkDrawable

<shape xmlns:android="http://schemas.android.com/apk/res/android"android:shape="rectangle">
    <solid android:color="?attr/colorPrimaryDark" />
</shape>

Espero que ajude!!


0

Como @marmor declarou, isso agora é compatível com a API 21. Mas para aqueles que precisam de suporte para versões legadas do Android, você pode usar este recurso. Usando a biblioteca de suporte v7, você ainda pode usá-la em aplicativos com nível mínimo de SDK até 7.

O AppCompatImageViewna Biblioteca de Suporte do Android v7 tem uma implementação livre de bugs desse recurso. Basta substituir seus usos de ImageViewpor AppCompatImageView.


2
Parece esperançoso! Mas o problema está na forma Drawable e não em uma visualização. Eu tenho uma visualização appcompat referenciando (como plano de fundo) uma forma que usa attr para obter uma cor temática e cai com o erro acima em <21. Há um drawable appcompat que perdi?
NeilS

Android 5.0.1 jy Huawei ainda afetado.
southerton
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.