Amigos, ótimo toda sexta-feira. Queremos compartilhar com você a tradução de um artigo preparado especialmente para os alunos do curso
“Android-developer. Curso avançado .
” Boa leitura.

Como declarativamente estilizar o texto no Android.
Ilustração de Virginia PoltrackTextView
em aplicativos Android fornece vários atributos para estilizar o texto e várias maneiras de aplicá-lo. Esses atributos podem ser configurados diretamente no layout, aplicar um estilo à visualização ou tema ao layout ou, se você desejar, definir textAppearance. Mas o que isso deve ser usado? E o que acontece se você combiná-los?
O que e quando usar?Este artigo descreve várias abordagens para estilização declarativa de texto (ou seja, quando você define estilos em um arquivo XML), discute o escopo e a prioridade de cada método.
tl; dr;
Você
deve ler o post inteiro, mas aqui está um resumo.
Lembre-se da ordem de prioridade dos vários métodos de estilo - se você estiver tentando estilizar algum texto e não encontrar os resultados esperados, provavelmente suas alterações serão substituídas por algo com uma prioridade mais alta nesta hierarquia:
Hierarquia de métodos de estilo de textoEu sugeriria o seguinte procedimento para estilizar:
- Defina qualquer estilo de aplicativo no
textViewStyle
como o estilo padrão para o seu tema. - Instale o conjunto (pequeno) de
TextAppearance
que seu aplicativo usará (ou usará / herdará dos estilos MaterialComponent) e faça referência a eles diretamente da sua exibição - Crie um
style
definindo atributos não suportados pelo TextAppearance
(que eles mesmos determinarão um dos seus TextAppearance
). - Execute qualquer estilo exclusivo diretamente no layout.
Mostre algum estilo
Você pode definir diretamente os atributos do
TextView
no layout, mas essa abordagem pode ser mais entediante e insegura. Imagine que dessa maneira você está tentando atualizar a cor de todos os TextViews no aplicativo. Como em todas as outras visualizações, você pode (e deve!) Usar estilos para garantir consistência, reutilização e facilidade de atualização. Para esse fim, recomendo criar estilos para texto sempre que você desejar aplicar o mesmo estilo a várias visualizações. Isso é extremamente simples e amplamente suportado pelo sistema de exibição do Android.
O que acontece quando você estiliza a vista? Se você já escreveu sua exibição personalizada, provavelmente viu a chamada para
context.obtainStyledAttributes (AttributeSet, int [], int, int) . Assim, o sistema de visualização no Android passa para a visualização os atributos especificados no layout. O parâmetro
AttributeSet
, de fato, pode ser considerado como um mapa dos parâmetros XML que você especifica em seu layout. Se o AttributeSet definir o estilo, o
estilo será lido primeiro e, em seguida, os atributos especificados diretamente na exibição serão aplicados a ele. Assim, chegamos à primeira regra de prioridade.
Exibir → EstiloOs atributos definidos diretamente na visualização sempre "prevalecem" e substituem os atributos definidos no estilo. Observe que uma
combinação de atributos de estilo e exibição é aplicada; definir um atributo na exibição, que também é especificado no estilo,
não cancela o estilo inteiro. Note-se também que, na sua opinião, não existe uma maneira real de determinar de onde vem a estilização; Isso é decidido pelo sistema de visualização para você uma vez em uma chamada semelhante. Você não pode obter as duas opções e escolher.
Embora os estilos sejam extremamente úteis, eles têm suas limitações. Uma delas é que você pode aplicar apenas um estilo à visualização (em oposição a algo como CSS, onde você pode aplicar várias classes).
TextView
, no entanto, tem um truque: fornece o atributo
TextAppearance
, que funciona de maneira semelhante ao
style
. Se você
style
texto por meio do
TextAppearance
, deixe o atributo
style
livre para outros estilos, o que parecerá prático. Vamos dar uma olhada no que
TextAppearance
e como ele funciona.
Textappearance
Não há nada mágico no
TextAppearance
(por exemplo, um modo secreto para aplicar vários estilos que você não deveria saber !!!!), o
TextView
evita que você trabalhe desnecessariamente. Vamos dar uma olhada no construtor
TextView
para entender o que está acontecendo.
TypedArray a = theme.obtainStyledAttributes(attrs, com.android.internal.R.styleable.TextViewAppearance, defStyleAttr, defStyleRes); TypedArray appearance = null; int ap = a.getResourceId(com.android.internal.R.styleable.TextViewAppearance_textAppearance, -1); a.recycle(); if (ap != -1) { appearance = theme.obtainStyledAttributes(ap, com.android.internal.R.styleable.TextAppearance); } if (appearance != null) { readTextAppearance(context, appearance, attributes, false); appearance.recycle(); }
Então, o que está acontecendo aqui? Basicamente, o
TextView
primeiro verifica se você especificou
android:textAppearance
;
android:textAppearance
caso, ele carrega esse estilo e aplica todas as propriedades listadas lá. Mais tarde, ele carrega todos os atributos da visualização (que ele lembra, incluindo o estilo) e os aplica. Então chegamos à segunda regra de prioridade:
Exibir → Estilo → Aparência de textoComo a aparência do texto é marcada primeiro, qualquer atributo definido diretamente na exibição ou no estilo o substituirá.
Com o
TextAppearance
, há outra
TextAppearance
: ele suporta um
subconjunto dos atributos de estilo que o
TextView
oferece. Para entender melhor o que quero dizer, vamos voltar a esta linha:
obtainStyledAttributes(ap, android.R.styleable.TextAppearance);
Vimos a versão
receiveStyledAttributes
com 4 argumentos, essa versão com 2 argumentos é um pouco diferente dela. Ela analisa o estilo fornecido (conforme definido pelo primeiro
id
parâmetro) e o filtra apenas de acordo com os atributos no estilo que aparecem no segundo parâmetro, o array
attrs
. O
android.R.styleable.TextAppearance
tão estiloso que define o escopo do
TextAppearance
. Observando essa definição, vemos que o
TextAppearance
suporta muitos,
mas não todos, atributos que o
TextView
suporta .
<attr name="textColor" /> <attr name="textSize" /> <attr name="textStyle" /> <attr name="typeface" /> <attr name="fontFamily" /> <attr name="textColorHighlight" /> <attr name="textColorHint" /> <attr name="textColorLink" /> <attr name="textAllCaps" format="boolean" /> <attr name="shadowColor" format="color" /> <attr name="shadowDx" format="float" /> <attr name="shadowDy" format="float" /> <attr name="shadowRadius" format="float" /> <attr name="elegantTextHeight" format="boolean" /> <attr name="letterSpacing" format="float" /> <attr name="fontFeatureSettings" format="string" />
Atributos de estilo suportados pelo TextAppearance
Aqui estão alguns atributos do
TextView
que não estão incluídos no
TextAppearance
:
lineHeight[Multiplier|Extra]
,
lines
,
breakStrategy
e
breakStrategy
.
TextAppearance
funciona no nível do caractere, não no nível do parágrafo; portanto, os atributos que afetam o layout inteiro não são suportados.
Portanto,
TextAppearance
muito útil, pois permite definir um estilo orientado para os atributos de estilização de texto e deixa o
style
à vista livre para outros fins. No entanto, ele tem um escopo limitado e está na parte inferior da cadeia de prioridades, portanto, não se esqueça das limitações.
Padrões razoáveis
Quando analisamos como a visualização Android resolve atributos (
context.obtainStyledAttributes
), na verdade simplificamos um pouco. Ela chama
theme.obtainStyledAttributes (usando o
Theme Context
atual 'a). Ao verificar o
link , a ordem de prioridade que examinamos anteriormente é mostrada e mais 2 locais são indicados que ele está procurando para resolver atributos: o estilo padrão da visualização e o tema.
Ao determinar o valor final de um atributo específico, quatro parâmetros de entrada entram em jogo:
- Qualquer valor de atributo neste AttributeSet.
- O recurso de estilo especificado no AttributeSet (chamado "style").
- O estilo padrão especificado por defStyleAttr e defstyleres
- Valores básicos neste segmento.
Ordem de prioridade de estilo a partir da documentação do temaVoltaremos aos temas, mas vamos dar uma olhada nos estilos padrão primeiro. Qual é esse estilo padrão? Para responder a essa pergunta, acho que seria útil fazer uma pequena saída do tema
TextView
e dar uma olhada em um simples
Button
. Quando você insere
<
Button
>
no layout, ele se parece com isso.
Botão PadrãoPorque Se você olhar o código fonte do
Button
, verá que ele é bastante escasso:
public class Button extends TextView { public Button(Context context) { this(context, null); } public Button(Context context, AttributeSet attrs) { this(context, attrs, com.android.internal.R.attr.buttonStyle); } public Button(Context context, AttributeSet attrs, int defStyleAttr) { this(context, attrs, defStyleAttr, 0); } public Button(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } @Override public CharSequence getAccessibilityClassName() { return Button.class.getName(); } @Override public PointerIcon onResolvePointerIcon(MotionEvent event, int pointerIndex) { if (getPointerIcon() == null && isClickable() && isEnabled()) { return PointerIcon.getSystemIcon(getContext(), PointerIcon.TYPE_HAND); } return super.onResolvePointerIcon(event, pointerIndex); } }
Isso é tudo! Aqui está toda a classe (sem comentários). Você pode conferir
você mesmo
aqui . Vou esperar Então, de onde vêm os antecedentes, letras maiúsculas, ondulações etc.? Você pode ter perdido, mas tudo será definido no construtor com 2 argumentos; aquele que é chamado quando o layout é obtido do XML. Este é o último parâmetro que define
defaultStyleAttr
em
com.android.internal.R.attr.buttonStyle
. Este é o estilo padrão, que é essencialmente um ponto de referência indireto, permitindo que você especifique o estilo padrão. Ele não aponta diretamente para o estilo, mas permite que você aponte para um dos especificados em seu tópico que ele verificará ao resolver atributos. E é exatamente isso que todos os temas dos quais você geralmente herda fazem para fornecer a aparência dos widgets padrão. Por exemplo, se você examinar o tópico Material, ele define
@style/Widget.Material.Light.Button
, e é esse estilo que fornece todos os atributos que
theme.obtainStyledAttributes
se você não especificou mais nada.
De volta ao
TextView
, ele também oferece um estilo padrão:
textViewStyle
. Isso pode ser muito conveniente se você deseja aplicar alguns estilos a cada TextView no seu aplicativo. Suponha que você queira definir o espaçamento de linha padrão como 1,2. Você pode fazer isso com
style/TextAppearance
e tentar aplicá-lo durante uma revisão de código (ou talvez até com uma regra personalizada elegante no Lint), mas você precisa estar atento e recrutar novos membros da equipe , tenha cuidado com a refatoração, etc.
Uma abordagem melhor seria especificar seu próprio estilo padrão para todos os
TextView
no aplicativo, definindo o comportamento desejado. Você pode fazer isso definindo seu próprio estilo para
textViewStyle
, que é herdado da plataforma ou de
MaterialComponents/AppCompat
por padrão.
<style name="Theme.MyApp" parent="@style/Theme.MaterialComponents.Light"> ... <item name="android:textViewStyle">@style/Widget.MyApp.TextView</item></style> <style name="Widget.MyApp.TextView" parent="@android:style/Widget.Material.TextView"> <item name="android:textAppearance">@style/TextAppearance.MyApp.Body</item> <item name="android:lineSpacingMultiplier">@dimen/text_line_spacing</item> </style>
Com isso em mente, nossa regra de prioridade assume a forma:
Ver -> Estilo -> Estilo Padrão -> Aparência de TextoComo parte da resolução dos atributos do sistema de exibição, esse espaço é preenchido após os estilos (para que tudo no estilo seja cancelado pelo estilo aplicado ou pelos atributos de exibição por padrão), mas ainda substitua a aparência do texto. Os estilos padrão podem ser muito convenientes. Se você decidir escrever sua própria exibição personalizada, ela poderá ser uma maneira poderosa de implementar o comportamento padrão, facilitando a personalização.
Se você herdar o widget e não especificar seu próprio estilo padrão, use o estilo de classe pai padrão nos construtores (não passe apenas 0). Por exemplo, se você herdar de
AppCompatTextView
e gravar seu próprio construtor com 2 argumentos, passe
android.R.attr.textViewStyle defaultStyleAttr
(
como aqui ), caso contrário você perderá o comportamento da classe pai.
Temas
Como mencionado anteriormente, existe outra (última, prometo) maneira de fornecer informações sobre o estilo. Outro
theme.obtainStyledAttributes
abordará diretamente o próprio tópico. Ou seja, se você adicionar um atributo de estilo ao seu tema, por exemplo
android:textColor
, o sistema de exibição o selecionará como último recurso. Como regra, é uma má idéia misturar atributos de tema e atributos de estilo, ou seja, o que você aplica diretamente à exibição, como regra, nunca deve ser definido para o tema (e vice-versa), mas existem algumas exceções raras.
Um exemplo seria quando você tenta alterar a fonte em todo o aplicativo. Você pode usar um dos métodos descritos acima, mas o ajuste manual dos estilos / aparência do texto em qualquer lugar será monótono e inseguro, e os estilos padrão funcionarão apenas no nível do widget; As subclasses podem substituir esse comportamento; por exemplo, os botões definem seu próprio
android:buttonStyle
, que seu
android:textViewStyle
não atenderá. Em vez disso, você pode especificar a fonte no seu tema:
<style name="Theme.MyApp" parent="@style/Theme.MaterialComponents.Light"> ... <item name="android:fontFamily">@font/space_mono</item> </style>
Agora, qualquer visualização que suporte esse atributo o buscará se não for substituída por algo com uma prioridade mais alta:
Exibir → Estilo → Estilo padrão → Tema → Aparência de textoNovamente, como isso faz parte do sistema de estilo de exibição, ele substituirá tudo o que é fornecido em forma de texto, mas será substituído por quaisquer atributos mais específicos.
Lembre-se desta prioridade. No nosso exemplo, com uma fonte para todo o aplicativo, você pode esperar que a
Toolbar
escolha essa fonte, pois ela contém o título, que é um
TextView
. A própria classe Barra de Ferramentas, no entanto, define um estilo padrão que contém
titleTextAppearance
, que define
android:fontFamily
, e o define diretamente no cabeçalho do
TextView
, substituindo o valor do nível do tema. Os estilos no nível do tópico podem ser úteis, mas fáceis de substituir, portanto, verifique se eles foram aplicados corretamente.
Bônus: problemas não resolvidos
Este artigo inteiro foi dedicado ao design declarativo do texto no nível da visualização, ou seja, como estilizar todo o
TextView
durante o preenchimento. Qualquer estilo aplicado após o preenchimento (por exemplo,
textView.setTextColor(…)
) substituirá o estilo declarativo.
TextView
também suporta estilos menores através do
Span
. Não vou entrar neste tópico, como é descrito em detalhes nos artigos de
Florina Muntenescu .
→
Estilo de texto fantasmático com vãos→
Vãos compreensivosMencionarei isso por questões de integridade, tendo em mente que o estilo e a extensão do programa estarão no topo da ordem de prioridade:
Extensão → Setters → Exibir → Estilo → Estilo padrão → Tema → Aparência de textoEscolha o seu estilo
Embora existam várias maneiras de estilizar seu texto, entender as diferenças entre os métodos e suas limitações ajuda a encontrar a ferramenta certa para uma tarefa específica ou a entender por que um método tem precedência sobre outro.
Tenha um bom estilo de texto!
Convidamos a todos para um
webinar gratuito no âmbito do qual conheceremos a estrutura DI Dagger 2: estudaremos como o Dagger2 gera código, lidaremos com as anotações JSR 330 e as construções Dagger2, aprenderemos como usar o Dagger2 em um aplicativo multi-módulo e consideraremos o Dagger Android Injector.