Quase todos os desenvolvedores sabem que existem Temas no Android, mas seu uso geralmente é limitado à cópia de partes de xml do Stack Overflow ou de outros recursos. Há informações na Internet sobre tópicos, mas isso geralmente é apenas uma receita de como alcançar um determinado resultado. Neste artigo, tentei fornecer uma visão geral introdutória do mecanismo de estilização do Android.
Conteúdo
1. IntroduçãoAtributos para o RectViewEstilo para o RectViewEstilo padrãoAtributo do tema de estilo RectViewTema do nível de atividadeExibir tópicoComo aplicar valores de atributoTópicos de RecursosSumário1. Introdução
Estilos e temas no android são mecanismos que permitem separar os detalhes do design (por exemplo, cor, tamanho da fonte etc.) da estrutura da interface do usuário. Para entender como isso funciona, um exemplo simples com visualização personalizada nos ajudará.
Precisamos de uma visualização personalizada simples que desenhe um retângulo com a cor desejada dentro dos limites da visualização.
class RectView @JvmOverloads constructor( context: Context, attrSet: AttributeSet? = null, defStyleAttr: Int = 0 ) : View(context, attrSet, defStyleAttr) { private val paint = Paint().apply { color = Color.BLUE } override fun onDraw(canvas: Canvas) { super.onDraw(canvas) canvas.drawRect(0f, 0f, width.toFloat(), height.toFloat(), paint) } }

Atributos para o RectView
Agora eu gostaria de poder alterar a cor do retângulo de layout.
Para fazer isso, precisamos adicionar um novo atributo, adicionar attrs.xml ao arquivo
<resources> <attr name="rectColor" format="color"/> </resources>
Agora, no código, podemos acessar o id desse atributo através de R.attr.rectColor e
no layout da tela, podemos usar o atributo app: rectColor.
<org.berendeev.themes.RectView android:id="@+id/text2" android:layout_width="100dp" app:rectColor="@color/colorPrimary" android:layout_height="100dp"/>
Mas o RectView ainda não sabe que existe um atributo no qual você pode tirar a cor do retângulo.
Vamos ensinar o RectView a entender o atributo rectColor, adicionar um grupo de atributos
<resources> <attr name="rectColor" format="color"/> <declare-styleable name="RectView"> <attr name="rectColor"/> </declare-styleable> </resources>
Na classe R, foram gerados 2 novos campos:
R.styleable.RectView é uma matriz de atributos de identificação, atualmente é uma matriz de um elemento R.attr.rectColor
R.styleable.RectView_rectColor é o índice de id do atributo na matriz R.styleable.RectView, ou seja, atributo id que podemos obter e, portanto, R.styleable.RectView [R.styleable.RectView_rectColor]
E adicione suporte ao atributo rectColor ao código.
init { val typedArray = context.theme.obtainStyledAttributes( attrSet, R.styleable.RectView, 0, 0 ) try { paint.color = typedArray.getColor( R.styleable.RectView_rectColor, Color.BLUE ) } finally { typedArray.recycle() } }
Código completo class RectView @JvmOverloads constructor( context: Context, attrSet: AttributeSet? = null, defStyleAttr: Int = 0 ) : View(context, attrSet, defStyleAttr) { private val paint = Paint().apply { color = Color.BLUE } init { val typedArray = context.theme.obtainStyledAttributes( attrSet, R.styleable.RectView, 0, 0 ) try { paint.color = typedArray.getColor( R.styleable.RectView_rectColor, Color.BLUE ) } finally { typedArray.recycle() } } override fun onDraw(canvas: Canvas) { super.onDraw(canvas) canvas.drawRect(0f, 0f, width.toFloat(), height.toFloat(), paint) } }
Agora podemos mudar a cor do retângulo no layout:

Estilo para o RectView
Agora, temos apenas um atributo, mas suponha que haja dez deles - seria extremamente inconveniente definir todos esses atributos no layout para elementos similares a cada vez.
A decisão de fazer tudo em grande estilo.
<style name="DefaultRectViewStyle"> <item name="rectColor">@color/colorAccent</item> </style>
Agora podemos criar qualquer tipo de visualização com a mesma aparência, especificando o estilo.
<org.berendeev.themes.RectView android:id="@+id/text2" android:layout_width="100dp" style="@style/DefaultRectViewStyle" android:layout_height="100dp"/>
Estilo padrão
Agora, queremos que todas as visualizações tenham algum tipo de estilo por padrão. Para fazer isso, especificaremos o estilo padrão para o método obtençãoStyledAttributes:
context.theme.obtainStyledAttributes( attrSet, R.styleable.RectView, 0, R.style.DefaultRectViewStyle )
Isso é o suficiente. Agora, todo o RectView que adicionamos ao layout terá o estilo padrão DefaultRectViewStyle.
Atributo do tema de estilo RectView
O valor padrão é bom, mas eu gostaria de controlar o layout com mais flexibilidade. É conveniente definir o estilo de uma visualização específica para todo o aplicativo ou para uma Atividade separada.
Para isso, precisamos de um novo atributo. Definiremos seu valor no tema, o valor será o estilo que determina a aparência do RectView.
<attr name="rectViewStyle" format="reference"/>
E ensine nosso rectView a entender esse atributo do tema. Passando o terceiro parâmetro R.attr.rectViewStyle para o método obtençãoStyledAttributes.
context.theme.obtainStyledAttributes( attrSet, R.styleable.RectView, R.attr.rectViewStyle, R.style.DefaultRectViewStyle )
Agora, se um item com o nome rectViewStyle e um valor do tipo style for especificado no tópico, esse estilo será aplicado a todos os RectView com esse tema.
Tema do nível de atividade
Definimos o valor do atributo rectViewStyle em nosso tópico.
<resources> <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar"> <item name="colorPrimary">@color/colorPrimary</item> <item name="colorPrimaryDark">@color/colorPrimaryDark</item> <item name="colorAccent">@color/colorAccent</item> <item name="rectViewStyle">@style/LocalRectViewStyle</item> </style> </resources>
Especifique o tópico no manifesto do aplicativo.
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="org.berendeev.themes"> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity> </application> </manifest>
Toda atividade será definida como o tema padrão do AppTheme. Definimos o design do RectView para todo o aplicativo.
O tópico também pode ser definido para uma atividade específica no manifesto.
<activity android:name=".MainActivity" android:theme="@style/MyTheme">
É importante aqui que o tema que definiremos no nível do aplicativo ou atividade seja herdado do tema padrão. Por exemplo, Theme.AppCompat. Caso contrário, ocorreremos falha no tempo de execução.
java.lang.IllegalStateException: você precisa usar um tema Theme.AppCompat (ou descendente) com esta atividade.
Exibir tópico
No nível da visualização, não reinstalamos o tema, mas substituímos os valores de atributo necessários, portanto, não precisamos herdar do tema padrão. Um pai pode estar vazio ou, por exemplo, podemos herdar uma das sobreposições ThemeOverlay.AppCompat.
Aqui, definimos o tema MyOverlay para o grupo LinearLayout e todos os seus descendentes na hierarquia.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:theme="@style/MyOverlay"> <org.berendeev.themes.RectView android:layout_width="100dp" android:layout_height="100dp"/> </LinearLayout>
No assunto, podemos prescindir dos pais, porque apenas modificamos o tema da atividade.
<style name="MyOverlay"> <item name="rectViewStyle">@style/LocalRectViewStyle</item> </style>
Como aplicar valores de atributo

Se para a visualização definirmos os valores dos atributos no layout, no estilo e no tema, a ordem de escolha do valor será a seguinte. A prioridade mais alta é o valor especificado no layout, ou seja, se o valor estiver definido no layout, o estilo e o tema serão ignorados, o estilo continuará, o tema e, finalmente, o estilo padrão.
Tópicos de Recursos
Os valores do tópico podem ser usados em recursos. Por exemplo, no drawable, podemos definir uma cor que dependerá da cor definida no tema.
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" > <solid android:color="?attr/colorPrimary"/> </shape>
Agora a cor do retângulo depende do valor do atributo colorPrimary no tema. O atributo pode ser qualquer um. Por exemplo, podemos definir nosso atributo em recursos e definir seu valor no assunto.
Esse truque pode ser usado em todos os recursos, por exemplo, no seletor ou no desenho vetorial. Isso torna o design mais estruturado e flexível. Podemos mudar rapidamente o tema para todas as atividades.
Sumário
- O tema e o estilo no nível do recurso são um e o mesmo, mas são usados de maneira diferente.
- Um tema pode conter outros temas, apenas significados ou estilos para a exibição.
- O estilo é indicado no layout no nível da vista. LayoutInflater calcula os valores de estilo e os passa como um AttributeSet para o construtor View.
- Temas é um mecanismo que permite definir a aparência globalmente para toda a atividade.
- Os valores do tópico podem ser alterados para o elemento (e descendentes) na hierarquia de visualizações.
- Os valores do tema podem ser usados não apenas no modo de exibição, mas também em recursos.
PS: se o artigo for interessante, escreverei um artigo mais avançado ou um artigo com muitos exemplos reais.