Como usar as novas cores dinâmicas no Material Design 3 do Android
Resumindo
Buscando renovar seu já conhecido Material Design, em maio de 2021, a Google anunciou sua mais nova versão do padrão de design que foi chamado de Material You, dentre outras novidades, ele trouxe o recurso de gerar paletas de cores baseadas no papel de parede do usuário e repassar isso para o sistema assim como para os apps instalados.
Então, hoje vamos:
- Conhecer o Material You / Material 3;
- Entender como as cores dinâmicas funcionam;
- Aplicar as cores dinâmicas a um app como um todo;
- Ver algumas peculiaridades dessa nova função.
Vamos lá?
Antes de prosseguir
Em 2021, além do Material You, a Google também apresentou o Jetpack Compose, que é um novo kit de ferramentas para criação de aplicativos Android. Embora a introdução das cores dinâmicas contida neste artigo possa ser útil ao lidar com Compose, faremos as implementações em um app que usa o sistema de views que está em uso na maioria dos aplicativos nativo atualmente.
Material You ou Material 3
Já explicamos, em um artigo anterior, os principais conceitos do Material Design, que é um conjunto de diretrizes de design sugerido pela Google para criação de layouts. Ou seja, especifica cores padrão, tamanho de botões etc.
O Material You é a terceira evolução desse conjunto de diretrizes e, por isso, também é conhecido como Material 3 (ou M3 como também é chamado) e traz mudanças para widgets, fontes, estilos e outros elementos comuns no desenvolvimento de interfaces.
Você pode aprender mais sobre as principais diferenças entre o Material 3 e sua versão anterior nesse guia oficial da Google.
Cores dinâmicas
A partir do Android 12, quando um papel de parede é aplicado, o sistema Android extrai as principais cores desse wallpaper e gera uma paleta (conjunto de cores diferentes) que pode ser usada tanto na interface do sistema, quanto também dentro de aplicativos para personalizar a experiência de usuário.
Além do wallpaper, podemos personalizar as cores de nosso app a partir do conteúdo dinâmico que ele exibe, por exemplo, a capa de um álbum de música:
Geração das paletas
Além das cores que podemos extrair do papel de parede e do conteúdo dinâmico dentro do app, também é possível:
- Gerar nossa própria paleta com tons semelhantes ao que o próprio sistema gera; e
- Fazer a customização que acharmos necessária.
Por exemplo, a partir da cor roxa (#5b49cd), temos a paleta para o tema claro e escuro:
Essas paletas podem ser geradas por meio do Material Builder, uma ferramenta oficial da Google que auxilia na criação e visualização de paletas que seguem o padrão do Material 3 e também permite fazer o upload de uma imagem e ver como suas cores serão extraídas/aplicadas à tela de um app de demonstração:
Você pode customizar manualmente cada uma das cores principais se desejar e, no fim, exportar um arquivo de temas em diferentes formatos que pode ser usado no Android (XML e Compose), Flutter, Web (CSS) ou no padrão DSP.
Para saber mais detalhes sobre como usar o Material Theme Builder, consulte este guia da documentação. Importante notar que não vamos usá-lo neste artigo, mas é uma ótima ferramenta para entender como essa nova função funciona.
Seja gerando as cores baseadas no papel de parede, conteúdo dinâmico ou mesmo pela ferramenta de criação de temas, o algoritmo usado vai garantir duas vantagens:
- Compatibilidade com o modo escuro;
- Paletas de cor que atendam aos requisitos de acessibilidade.
Agora, é importante que você se atente a dois pontos importantes.
Avisos
É bom frisar que a função de cores dinâmicas está disponível apenas para dispositivos que possuam o Android 12 ou superior. Outro detalhe importante é que, para que as cores dinâmicas tenham o resultado esperado, é preciso garantir que não haja cores codificadas permanentemente no aplicativo; nossos componentes devem receber as cores via tema e não diretamente no layout ou via código. Combinado?
Considerados esses avisos, vamos colocar a mão na massa (ou melhor dizendo, no código)!
Colocando a mão na massa: como personalizar cores no Material Design 3
Agora é hora de colocar a mão na massa e descobrir como personalizar cores e widgets no Material Design 3.
Pensando em facilitar o seu entendimento do assunto, vamos utilizar um aplicativo pronto: o Orgs, que foi desenvolvido no Curso de Android com Kotlin persistência de dados com o Room, e simula um e-commerce de produtos orgânicos.
Passo 1): Como atualizar o Material Design 2 para Material Design 3 no aplicativo
Segundo o guia oficial para implementação das cores dinâmicas, o primeiro passo a se fazer é atualizar o projeto do aplicativo para o Material Design 3. Nosso aplicativo possui uma versão mais antiga do Material, porém caso seu projeto não o possua, confira essas instruções de introdução aos componetes do Material Design para Android.
No seu projeto, abra o arquivo build.gradle
do módulo app
, e atualize a dependência do Material para pelo menos 1.5.0-alpha04 (no momento em que esse artigo é escrito a versão atual é 1.6.1):
dependencies {
// outras dependências …
implementation 'com.google.android.material:material:1.6.1'
// outras dependências …
}
Neste mesmo arquivo, altere as opções compileSdkVersion
e targetSdkVersion
para, pelo menos, 31 (número da API do Android 12):
android {
compileSdkVersion 31
// outros códigos …
defaultConfig {
// outros códigos …
targetSdkVersion 31
}
}
Nos arquivos de temas do Orgs, faça com que tudo que usa Theme.MaterialComponents
agora passe a usar Theme.Material3
, então, dentro do arquivo themes.xml
, localizado em res\values
, antes era assim:
<resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base application theme. -->
<style name="Theme.Orgs" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
// outros atributos…
</resources>
Agora, passa ser assim:
<resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base application theme. -->
<style name="Theme.Orgs" parent="Theme.Material3.DayNight">
// outros atributos…
</resources>
Faça a mesma modificação para outros arquivos que contenham uma referência semelhante, como o de tema escuro.
Os atributos entre as versões do Material podem ser diferentes como a Documentação explica. Assim, a tabela a seguir mostra a equivalência entre alguns atributos da versão antiga com a mais nova para auxiliar nesta troca:
MaterialComponents | Material3 |
---|---|
Theme.MaterialComponents.Light | Theme.Material3.Light |
Theme.MaterialComponents.Light.NoActionBar | Theme.Material3.Light.NoActionBar |
Theme.MaterialComponents | Theme.Material3.Dark |
Theme.MaterialComponents.NoActionBar | Theme.Material3.Dark.NoActionBar |
Theme.MaterialComponents.DayNight | Theme.Material3.DayNight |
Theme.MaterialComponents.DayNight.NoActionBar | Theme.Material3.DayNight.NoActionBar |
Theme.MaterialComponents.Light.DarkActionBar | Não existe |
Theme.MaterialComponents.DayNight.DarkActionBar | Não existe |
Passo 2: Como personalizar cores e Widgets no Material Design 3
Agora, com a versão do Material atualizada, podemos focar no que interessa! Ao realizar essa mudança e rodar o app, podemos perceber mudanças significativas na tela:
É possível perceber dois tipos principais de mudanças:
1) Mudanças estéticas e de layout: como o botão, que no Material 2 tinha formato redondo e, agora, no Material 3, é quadrado com cantos arredondados.
2) Mudanças em como as cores são tratadas: há duas mudanças principais, segundo a documentação. O primeiro ponto é sobre atributos que continuam em uso e atributos que foram descontinuados:
O sistema de cores do Material 3 usa uma abordagem organizada para aplicar cores à sua interface do usuário. Vários atributos de Theme.AppCompat ainda estão em uso. No entanto, mais atributos foram adicionados Theme.MaterialComponents. e ainda mais, Theme.Material3. por isso é importante examinar todas as telas do seu aplicativo para garantir que nenhuma propriedade não implementada esteja saindo do tema base.
O texto acima é complementado pela tabela que relaciona os atributos antigos com os mais novos, e inclusive indica que o padrão colorPrimaryVariant
foi descontinuado, então vamos removê-lo do nosso tema e do nosso arquivo de cores para garantir que a cores dinâmicas funcionem melhor:
<!-- outros atributos do color.xml -->
<item name="colorPrimary">@color/colorPrimary</item>
remover essa linha >>> <item name="colorPrimaryVariant">@color/colorPrimaryVariant</item>
<item name="colorOnPrimary">@color/colorOnPrimary</item>
<!-- outros atributos -->
<!-- outros atributos do themes.xml -->
<item name="colorPrimary">@color/colorPrimary</item>
remover essa linha >>> <item name="colorPrimaryVariant">@color/colorPrimaryVariant</item>
<item name="colorOnPrimary">@color/colorOnPrimary</item>
<!-- outros atributos -->
O segundo ponto relacionado às mudanças no tratamento de cor é que o Material 3 usa um tom roxo para as cores de destaque padrão se as cores dinâmicas não estiverem disponíveis.
Isso fica claro ao compararmos o floating action button
da imagem anterior que antes era verde e agora está roxo claro. Para mudar isso (por questões de marca por exemplo), no color.xml
, adicione os seguintes atributos com as cores de nossa escolha:
<!-- outros atributos -->
<color name="colorPrimaryContainer">#4CAF50</color>
<color name="colorOnPrimaryContainer">#FFFFFF</color>
<!-- outros atributos -->
E, no themes.xml
, faça referência a essas cores:
<!-- outros atributos -->
<item name="colorPrimaryContainer">@color/colorPrimaryContainer</item>
<item name="colorOnPrimaryContainer">@color/colorOnPrimaryContainer</item>
<!-- outros atributos -->
Note que adicionamos dois atributos de cor, um para o fundo do botão colorPrimaryContainer
e outro para seu ícone colorOnPrimaryContainer
. Mas por qual razão? Bem, isso foi feito para manter um bom contraste pensando em acessibilidade e manter consistência visual.
Caso você tenha dúvidas sobre quais cores são usadas por um componente específico, consulte essa seção da documentação.
Por fim, os Cards no Material 3, por padrão, apresentam uma borda em volta. Para mudar isso, adicionamos um atributo de estilo às implementações desse widget:
<com.google.android.material.card.MaterialCardView
<!-- outros atributos -->
style="?attr/materialCardViewFilledStyle">
O MaterialCardViewFilledStyle é um dos estilos que podem ser implementados para os cards; cada estilo também terá um padrão de cor no tom de roxo e, mais uma vez, para personalizar isso, caso seja necessário, adicione um atributo ao arquivo de cor (no caso de exemplo, a cor escolhida será o branco, que faz parte da identidade visual do aplicativo Orgs):
<!-- outros atributos -->
<color name="colorSurfaceVariant">#FFFFFF</color>
<!-- outros atributos -->
E o referenciamos no arquivos de temas:
<!-- outros atributos -->
<item name="colorSurfaceVariant">@color/colorSurfaceVariant</item>
<!-- outros atributos -->
Agora temos:
Nós mudamos algumas cores e o estilo dos cards que exibem os itens para que o layout desse app em específico atenda ao visual que esperamos. Vale ressaltar que, na sua implementação, pode ser necessário fazer outros ajustes, então recomendamos que consulte a documentação oficial do Material Design 3.
Como adicionar cores dinâmicas no Material Design 3 do Android
Passo 1): Crie um arquivo de classe que estenda de Application
. Em nosso exemplo, chamamos esse arquivo de ‘OrgsApplication’, e sua função é ser responsável por aplicar as cores dinâmicas no app (caso elas estejam disponíveis):
class OrgsApplication : Application() {
override fun onCreate() {
super.onCreate()
DynamicColors.applyToActivitiesIfAvailable(this)
}
}
Passo 2): Faça a essa classe no AndroidManifest.xml
do app, então, dentro dele, procure a procure a tag application
e adicione o atributo android:name apontando para o local de nosso arquivo recém-criado:
<?xml version="1.0" encoding="utf-8"?>
<manifest …
<application
android:name=".OrgsApplication"
<!-- outros códigos -->
</application>
</manifest>
Nossa configuração está pronta! Como resultado, ao trocar o papel de parede e reabrir o aplicativo, suas cores são alteradas:
Como adicionar cores dinâmicas a componentes específicos no Material 3 do Android
A UI (interface do usuário) do Orgs está adaptada para as cores dinâmicas, mas nem todos os elementos serão influenciados pela paleta de cores gerada pelo sistema. Pode ser do nosso interesse que, por exemplo, um texto, um widget ou mesmo o fundo de uma tela também apresente o comportamento de mudar cor conforme o wallpaper.
As cores dinâmicas extraídas a que temos acesso são divididas em cinco categorias, sendo três cores de destaque e duas cores neutras:
Cada uma dessas cores possui uma variação de tom do mais claro para o mais escuro e são identificadas pelos números: 0, 10, 50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000.
Em qualquer lugar de nossos layouts, podemos acessar a propriedade @android:color/system_accent
ou @android:color/system_neutral
e suas variações para obter acesso a uma cor dinâmica atual, por exemplo, em nossa activity principal activity_lista_produtos_activity.xml
vamos colocar um background:
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
<!-- outros atributos -->
android:background="@android:color/system_accent1_300"
tools:targetApi="s">
<!-- restante do código -->
Veja como nosso app ficou com um papel de parede roxo e outro verde respectivamente:
Note que, no código anterior, usamos o namespace tools:targetApi="s
” para permitir a adição de cores dinâmicas em um layout que pode não estar rodando em um aparelho com suporte a essa função. Isso não é o ideal, mas permite que o app continue funcionando normalmente em versões anteriores do Android, como no 10, por exemplo:
Uma maneira mais correta de lidar com essa situação é criar um arquivo attrs.xml
dentro do diretório values
de seu app e, nele, definir uma propriedade que lidará com a cor de fundo:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<attr name="backgroundColor" format="color"/>
</resources>
O nome backgroundColor
pode ser qualquer coisa como corApenasDosBotõesRedondos
; o importante é que format
seja do tipo color.
Agora, vamos criar um arquivo de temas a que só versões do Android 12 ou superior tenham acesso:
Passo 1): Clique com botão direito em cima da pasta values (que está dentro de res), selecione New e depois Values Resource File.
Passo 2): Na janela que surgirá em File name, coloque o nome themes e, no campo Directory name, deixe como values-v31:
Clique em ok e o arquivo criado será aberto contendo um código similar a este:
<?xml version="1.0" encoding="utf-8"?>
<resources></resources>
Passo 3): Precisamos que esse tema herde as mesmas características de nosso tema base. Para fazer isso, crie uma tag style
que possua o mesmo name
e parent
do arquivo de temas que viemos trabalhando ao longo do artigo:
<resources >
<style name="Theme.Orgs" parent="Theme.Material3.DayNight">
</style>
</resources>
Passo 4): Dentro da tag style
, faça referência à propriedade que criamos em attrs.xml e apontamos para cor dinâmica escolhida (@android:color/system_accent1_300
, no nosso caso):
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools">
<style name="Theme.Orgs" parent="Theme.Material3.DayNight">
<item name="backgroundColor" >@android:color/system_accent1_300</item>
</style>
</resources>
Passo 5): Na activity_lista_produtos_activity.xml
, coloque, no atributo de background
, a referência ao ?attr/backgroundColor
e não mais diretamente a cor, eliminando também a necessidade de usar o tools:targetApi="s"
:
<androidx.constraintlayout.widget.ConstraintLayout
<!-- outros atributos -->
android:background="?attr/backgroundColor">
<!-- restante do código -->
Pronto! O arquivo de tema exclusivo do Android 12 está criado. O resultado é o mesmo de quando adicionamos a propriedade android:background="@android:color/system_accent1_300"
diretamente ao nosso arquivo de layout anteriormente, mas fizemos o uso de uma abordagem altamente recomendada, com as vantagens de:
- Permitir aplicar esse mesmo tema a outras telas caso desejarmos;
- Dar suporte a criação de temas escuros com comportamentos equivalentes se necessário.
E ah, claro! Mantemos a compatibilidade com versões anteriores do Android:
Pronto! Vimos várias dicas para usar as novas cores dinâmicas do Material 3 no Android, seja na sua versão atual - da data de publicação deste artigo - ou anterior.
Um último detalhe: TopApp
O Material Design traz inúmeros novos padrões de cor e estilos que impactam muito alguns aspectos que já estamos acostumados, e vimos muito isso ao longo deste tutorial. A AppBar - que antes trazia cores mais vibrantes -, agora traz tons mais suaves como regra; esse é um novo padrão sugerido pela Google que inclusive pode ser visto em seus próprios aplicativos:
Por questões de marca, você pode selecionar uma cor específica da AppBar. Ao fazer isso, perdemos um elemento de interação importante com as cores dinâmicas. Por outro lado, ao não fazer, temos que prestar atenção às telas que possuem ícones de menu e mudar a cor dos ícones, para que contrastem melhor com o fundo e sejam mais visíveis.
Você, inclusive, pode optar por uma abordagem semelhante à usada anteriormente para mudar o fundo da tela, em que temos uma cor padrão para quando as cores dinâmicas não estão disponíveis e, outra, para quando estão:
Conclusão
Neste artigo, foram muitos aprendizados:
- Saber o que são e como funcionam as cores dinâmicas;
- Conhecer mais sobre o novo Material Design 3 ou “Material You”, como a Google o nomeou;
- Adaptar um aplicativo para que passe a fornecer suporte a essa nova função;
- Aplicar algumas técnicas ao realizar a atualização do Material em outros layouts.
Recomendamos muito que você separe um tempo e leia a documentação do Material 3 que é bem detalhada e pode ser útil em casos mais pontuais.
Para aprender mais sobre a programação de apps Android, lembre de conferir nos nossos cursos da Formação Mobile.
Muito obrigado pela presença e até mais!