Criando um tema customizável com Jetpack Compose!

Lucas Yuji Yoshimine
Android Dev BR
Published in
4 min readOct 28, 2021

--

Por padrão, o Jetpack Compose usa o Material Design para realizar temas, ele é ótimo e contém um design system bem implementado e consistente, e seu uso é bastante simples com o Compose.

Este é o método composable do MaterialTheme, que contém 4 parâmetros, sendo: colors, typography, shapes e content. Cada um deles é possível de implementar as cores, tipografias e formas que desejam desde que sigam o padrão do Material. Entretanto, as vezes o padrão que ele oferece não é o suficiente para o uso, e com isso vem a dúvida… Como criar um próprio tema que se mantenha no contexto como Material Design?

Criando o próprio tema!

Para isso, é preciso entender um pouco de como o Material funciona por "debaixo dos panos":

Este objeto contém todas as propriedades passadas no método MaterialTheme, eles que dão o suporte de quando se necessita utilizar algo do tema dentro do contexto que o abrange. Sabendo disso, criaremos o nosso próprio objeto customizado.

Neste exemplo, foi adicionada uma propriedade chamada spaces para exemplificar, que contém o tipo CustomSpaces e terá o papel de realizar os espaçamentos (margens) dentro do tema. Também foi atribuído para colors como CustomColors, que será uma classe criada posteriormente. Além disso, as atribuições (Locals) serão implementadas depois.

Neste exemplo, o customSpaces é usado com as seguintes propriedades:

  • Small
  • Medium
  • Large
  • Extra large

Para a tipografia, o customTypography é utilizado com as seguintes propriedades:

  • H1 (Headline 1)
  • Body1

Por fim, a customColors utilizam-se das respectivas propriedades:

  • Primary
  • Text
  • Background
  • Success
  • Error
  • isLight

Por que usar MutableStateOf nesse caso?

O MutableStateOf cria um valor armazenado no cache, evitando que o composable fique recompondo toda vez que o método é chamado pelo composable, e apenas é emitida para UI quando o seu valor é atualizado, por isso necessitamos do seu uso para guardar os estados das cores e mantê-las dinâmicas.

Pelo fato de utilizar um MutableState, não se pode criar uma Data Class, porém serão criados os métodos copy e updateColorsFrom para a necessidade futura.

Após a criação do objeto, chegou a vez de armazenar os valores no objeto que foi criado, e para isso, é necessário utilizar o CompositionLocal, de grosso modo, serve para prover os dados quando estiver dentro de um contexto, precisando ser injetado apenas uma vez para o seu uso. Por ser estático, será usufruído o método staticCompositionLocalOf, sabendo também que não é preciso (ou quase nunca) mudar os valores depois que usados pelo provider, além de que a performance melhora consideravelmente.

lightColors/darkColors são métodos no quais retornam CustomColors personalizados, caso fique com dúvidas de como implementar, clique aqui para ver no projeto.

Após isso, é necessário apenas criar o método CustomTheme, que será implementado no projeto. Para prover o CompostionLocal, é usado o método CompositionLocalProvider, que aceita N providers. Também é colocado o método ProvideTextStyle para que o tema já inicie com um estilo de texto padrão (no exemplo é o body1).

Neste momento, é preciso dos métodos copy/updateColorsFrom de CustomColors, pois eles são necessários para evitar que o estado inicial das cores não alterem seu valor original depois que fornecida, ou seja, o copy cria uma outra instância da classe para que não haja vínculo por referência, e o updateColorsFrom serve como um “double-check” para evitar recomposições dentro do sistema, fazendo com que todos os mutableStateOf tenham um valor armazenado. O método ficará dessa maneira:

Caso queira adicionar suporte para Dark Theme (System), há esse outro método no qual darkColors é um parâmetro opcional:

agora o content conseguir irá usufruir totalmente do tema aplicado e caso queira usar alguma propriedade, lembre-se de utilizar o objeto CustomTheme para resgatar o valor.

Resultado

Preview custom themes

Conclusão

Temas são importantes e muito utilizados no dia a dia do desenvolvedor e o Jetpack Compose acertou em cheio ao deixar algo customizável e fácil de ser implementado. E lembre-se, a criação do tema deu-se pelo Composition Local Provider, porém ele é capaz de realizar muitas outras coisas, por exemplo o insets do Google accompanist que também o utiliza.

Repositório do projeto

Caso tenha ficado com alguma dúvida, tanto no nível de aplicação quanto de como a UI foi realizada, segue logo abaixo o link para o repositório com a implementação deste artigo.

https://github.com/ujizin/custom-themes

--

--