Por exemplo, o botão padrão possui as seguintes dependências entre seus estados e imagens de plano de fundo:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_window_focused="false" android:state_enabled="true"
android:drawable="@drawable/btn_default_normal" />
<item android:state_window_focused="false" android:state_enabled="false"
android:drawable="@drawable/btn_default_normal_disable" />
<item android:state_pressed="true"
android:drawable="@drawable/btn_default_pressed" />
<item android:state_focused="true" android:state_enabled="true"
android:drawable="@drawable/btn_default_selected" />
<item android:state_enabled="true"
android:drawable="@drawable/btn_default_normal" />
<item android:state_focused="true"
android:drawable="@drawable/btn_default_normal_disable_focused" />
<item
android:drawable="@drawable/btn_default_normal_disable" />
</selector>
Como posso definir meu próprio estado personalizado (como smth android:state_custom
), para poder usá-lo para alterar dinamicamente a aparência visual do botão?
Respostas:
A solução indicada por @ (Ted Hopp) funciona, mas precisa de uma pequena correção: no seletor, os estados do item precisam de um prefixo "app:"; caso contrário, o inflador não reconhecerá corretamente o espaço para nome e falhará silenciosamente; pelo menos é o que acontece comigo.
Permita-me relatar aqui toda a solução, com mais alguns detalhes:
Primeiro, crie o arquivo "res / values / attrs.xml":
Em seguida, defina sua classe personalizada. Por exemplo, pode ser uma classe "FoodButton", derivada da classe "Button". Você terá que implementar um construtor; implemente este, que parece ser o usado pelo inflador:
No topo da classe derivada:
Além disso, suas variáveis de estado:
E alguns levantadores:
Em seguida, substitua a função "onCreateDrawableState":
Finalmente, a peça mais delicada deste quebra-cabeça; o seletor que define o StateListDrawable que você usará como plano de fundo para seu widget. Este é o arquivo "res / drawable / food_button.xml":
Observe o prefixo "app:", enquanto que com os estados padrão do android você usaria o prefixo "android:". O espaço para nome XML é crucial para uma interpretação correta do inflador e depende do tipo de projeto no qual você está adicionando atributos. Se for um aplicativo, substitua com.mydomain.mypackage pelo nome do pacote real do seu aplicativo (nome do aplicativo excluído). Se for uma biblioteca, você deverá usar "http://schemas.android.com/apk/res-auto" (e usar o Tools R17 ou posterior) ou obterá erros de tempo de execução.
Algumas notas:
Parece que você não precisa chamar a função "refreshDrawableState", pelo menos a solução funciona bem como está, no meu caso
Para usar sua classe personalizada em um arquivo xml de layout, você precisará especificar o nome completo (por exemplo, com.mydomain.mypackage.FoodButton)
Você pode misturar estados padrão (por exemplo, android: pressionado, android: ativado, android: selecionado) com estados personalizados, a fim de representar combinações de estado mais complicadas
fonte
refreshDrawableState
é definitivamente importante. Não tenho certeza absoluta de quando é realmente necessário. Mas no meu caso, isso foi necessário ao definir o estado programaticamente. Eu acho que é possivelmente chamado da classe View automaticamente no onTouchEvent. É melhor adicioná-lo no método setSelected.boolean
? Ou os seletores estão operando apenas em booleanos?Este tópico mostra como adicionar estados personalizados a botões e similares. (Se você não conseguir ver os novos grupos do Google no seu navegador, há uma cópia do tópico aqui .)
fonte
Não se esqueça de ligar
refreshDrawableState
dentro do thread da interface do usuário:Demorou muito tempo para descobrir por que meu botão não está mudando de estado, mesmo que tudo pareça certo.
fonte