Como utilizar temas no Flutter - Parte 2
Na primeira parte dessa série sobre como utilizar temas no Flutter, vimos alguns conceitos básicos de temas, aprendemos os conceitos de surface e background e utilizamos o ThemeData para personalizar as nossas aplicações.
Essa utilização mais básica pode ser bem legal para projetos pessoais ou pequenos que não tenham muitos desenvolvedores envolvidos no desenvolvimento da UI da aplicação.
Quando a aplicação começa a ganhar volume de usuários, código e também relevância nas lojas, torna-se cada vez mais importante pensarmos em como deixá-la mais fácil de dar manutenção, de ser entendida por todos os envolvidos no projeto e, também, como evitar que sejam utilizados tokens diferentes para as mesmas funções ou contextos.
Pensando nisso, como podemos fazer se temos uma aplicação grande ou um sistema de design complexo e precisamos garantir que todas as pessoas envolvidas no projeto utilizem as mesmas cores e estilos de texto?
Vem comigo que hoje vamos falar sobre temas personalizados de maneira mais avançada! Are you ready? Let's go!
Um pequeno disclaimer
Por conta da complexidade do assunto, utilizarei como base para este artigo as práticas aplicadas nas aplicações Flutter da Revelo e aprendizados que tivemos ao longo do tempo.
Utilizando tokens para um tema geral de aplicação
Na Revelo, organizamos nossos temas a partir de duas classes de tokens: Colors e Typography. Isso nos ajudará a ter esses tokens (de cor e texto) centralizados em um só lugar, tornando sua manutenção mais fácil. Já passamos por dois rebrandings na nossa app e essas classes ajudaram muito!
Colors
Uma classe Colors será composta pelos tokens de cor que o seu time de design definiu e será a fonte da verdade em relação a eles. Idealmente, você deve evitar utilizar cores que não estejam nesta classe, ou seja, não foram definidas pelo seu time de design. Também recomendo como uma boa prática evitar utilizar esses tokens diretamente nos seus widgets, mas sim utilizar a camada de temas para isso, ok?
Por aqui tenho duas dicas principais:
1) Utilize numeração para poder definir tons de cor e não superlativos. Por exemplo:
2) Nomeie os tokens dessa classe de acordo com a cor ou função muito específica. Ainda não é a hora de definir cores primárias ou secundárias.
Typography
Uma classe Typography será composta pelos tokens de texto que o seu time de design definiu, como a família da fonte, peso e altura do texto. Como na classe Colors, essa classe será a fonte da verdade em relação a tipografia da sua app.
Vou me repetir um pouco aqui, mas é importante: idealmente, você deve evitar utilizar tokens de tipografia que não estejam nesta classe, ou seja, não foram definidos pelo seu time de design. Se tiver uma tipografia nova, adicione-a nessa classe. Também retorno com a recomendação de evitar utilizar esses tokens diretamente nos seus widgets, mas sim, utilizar a camada de temas para isso, ok?
Vale notar:
- Com essa classe, temos um local centralizado onde podemos alterar a nossa tipografia de uma vez só - seja altura do texto, tamanho da fonte ou peso dela.
- É legal utilizarmos tokens de texto para emojis com height = 1, assim evitamos que o tamanho deles fique desproporcional ao texto que os esteja acompanhando.
- Note que, nos tokens de texto, não definimos as cores deles. Deixaremos este trabalho para o tema.
Ok, agora já temos classes específicas para os nossos tokens de cor e texto. Porém, isso ainda não atende a nossa necessidade de manutenibilidade e usabilidade pelas pessoas desenvolvedoras do nosso time, né? Quando temos contextos diferentes para a mesma cor, adicionamos uma cor nova para cada um dos seus usos ou utilizamos uma camada extra, que podemos inclusive estender e sobrescrever?
Para responder estas perguntas, vamos falar agora sobre a centralização desses tokens em um tema personalizado. Vem comigo!
Consolidando um tema personalizado de estilos e cores
O que faremos agora é criar uma classe de tema, que será a centralização dos tokens e também poderá aplicar mudanças a eles, criando tokens com funcionalidades específicas. Ela vai ser a camada extra que mencionei acima, permitindo uma personalização maior do uso de cores sem ficar com tokens duplicados. Acredite, seu time de design vai amar quando você tiver isso na sua app.
Vamos ver como podemos fazer com os tokens de cor:
Como você pode ver, agora temos cores com funções de acordo com o design, como as cores primárias e secundárias, cores de botão, cor de destaque (featuredColor) e cores de contraste para serem utilizadas em textos.
Falando em textos, vamos ver como ficam alguns estilos de texto para o nosso tema?
Aqui, perceba que temos algumas coisas interessantes, como o txBody normal com cores de contraste highContrast, mediumConstrast e lowContrast (disabledColor). Ainda com a mesma fonte, temos o txBody com highEmphasis, que utiliza a tipografia bold ao invés da normal.
Então, a classe final pode ser:
Prontinho, agora você tem um tema para chamar de seu. Mas como vamos utilizá-lo de maneira eficiente? Te explico no próximo tópico.
Widget de tema personalizado e ThemeWrapper (avançado)
Garantindo a presença do tema no context com um widget de tema personalizado
Vamos utilizar a classe InheritedWidget do Flutter para podermos manter as informações do nosso tema disponíveis no contexto certo da Widget Tree. Com isso, poderemos acessar os tokens que definimos no tema de maneira mais fácil, sem precisarmos instanciar a classe todas as vezes.
Nossa classe de tema personalizado dependerá do tema que definimos na última seção (GeneralAppTheme) e, para podermos garantir que o contexto será definido corretamente, também adicionaremos um parâmetro de tipo Widget chamado child por conta do InheritedWidget.
Nossa classe ficará assim:
A função estática of servirá para acessarmos o nosso tema mais facilmente e o updateShouldNotify fará a árvore ser reconstruída caso o tema seja alterado.
Para utilizar esse tema, é simples:
ThemeWrapper
Já está legal, mas vamos deixar ainda melhor? Vamos fazer um Wrapper para esse tema, ele vai facilitar sua utilização e evitar que você esqueça de utilizar o Builder para ter o contexto correto.
A classe (na verdade, Widget) é bem simples:
A sua utilização também é simples! Olha só:
Temas para wigdets específicos (avançado)
Agora digamos que você não quer ter um tema que possua cada uso de cores ou estilos diferente para cada widget, por exemplo: se eu tenho um botão azul, terei uma blueButtonColor
e se eu tenho um botão vermelho terei mais um token no tema, como uma redButtonColor
. Com apps maiores, gerenciar e dar manutenção em todos esses temas dentro de widgets começa a ficar bem complexo e, como devs, não é isso que queremos.
Vamos então criar dois temas de botão, um azul e um vermelho, que modificarão o token elevatedButtonColor do nosso tema principal.
Estes temas podem ser utilizados da mesma maneira do GeneralAppTheme:
Fácil, não? :)
Conclusão
É isso aí! Agora sim você está craque de temas e conseguirá organizar seus tokens, temas personalizados para widgets específicos e seus projetos como um todo de uma maneira muito mais replicável e manutenível.
Esta série de artigos foi um resumo mais detalhado dos meus aprendizados sobre temas no Flutter dentro da Revelo. Obrigado por me acompanhar nessa jornada! Fica aqui também o meu agradecimento ao Cesar Castro e ao Douglas Iacovelli por terem me ensinado MUITO do que eu mostrei aqui para você!
Espero que tenha conseguido te ajudar consolidar seu conhecimento sobre como utilizar temas no Flutter. Me conta o que você achou e, se tiver dúvidas ou sugestões, pode me chamar no LinkedIn ou no e-mail que conversamos, tá bom?
Obrigado!
A Revelo Content Network acolhe todas as raças, etnias, nacionalidades, credos, gêneros, orientações, pontos de vista e ideologias, desde que promovam diversidade, equidade, inclusão e crescimento na carreira dos profissionais de tecnologia.