<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Joabe Ramone</title>
    <description>The latest articles on Forem by Joabe Ramone (@joaberamone).</description>
    <link>https://forem.com/joaberamone</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F409779%2Fbd5f8ed3-d519-4861-846d-3740dffb0b9a.jpeg</url>
      <title>Forem: Joabe Ramone</title>
      <link>https://forem.com/joaberamone</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/joaberamone"/>
    <language>en</language>
    <item>
      <title>Firebase auth keytool Opção inválida</title>
      <dc:creator>Joabe Ramone</dc:creator>
      <pubDate>Fri, 27 Aug 2021 01:02:19 +0000</pubDate>
      <link>https://forem.com/joaberamone/firebase-auth-keytool-opcao-invalida-1mkb</link>
      <guid>https://forem.com/joaberamone/firebase-auth-keytool-opcao-invalida-1mkb</guid>
      <description>&lt;h2&gt;
  
  
  Introdução
&lt;/h2&gt;

&lt;p&gt;Fala clan, tudo bem?&lt;/p&gt;

&lt;p&gt;Quero mostrar rapidinho como resolvi um problema daquele comando inválido para criar as chaves SHA do Projeto do Firebase. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fLaNFZpp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yih9dhtu0dqhb6r58co7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fLaNFZpp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yih9dhtu0dqhb6r58co7.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Quando eu estava rodando esse comando &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;keytool -list -v \&lt;br&gt;
-alias androiddebugkey -keystore %USERPROFILE%.android\debug.keystore&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Apresentava este erro dizendo que a opção keytool era inválida.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--hYsD26WZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s8agg3f59um2kdqhpxe5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hYsD26WZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s8agg3f59um2kdqhpxe5.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Isso acontece porque eu não tinha a variavel de ambiente, então você tem que criar essa variavel que é basicamente o caminho de onde está o keytool. &lt;/p&gt;

&lt;h2&gt;
  
  
  Como resolver
&lt;/h2&gt;

&lt;p&gt;E ele fica dento da pasta Java, que geralmente é esse caminho: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;C:\Program Files\Java\jdk1.8.0_291\bin&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--HWS_HSky--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ppfrkvuygbwbew3zvi7a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--HWS_HSky--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ppfrkvuygbwbew3zvi7a.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Copie esse caminho, vá em &lt;strong&gt;Editar as variváveis de ambiente do sistema&lt;/strong&gt;, clique em Variáveis de ambiente &amp;gt; path (2 cliques) &amp;gt; novo &amp;gt; cole o caminho &amp;gt; ok.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9WfmBh2F--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ku8f8uoq1mbvfzd6amlg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9WfmBh2F--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ku8f8uoq1mbvfzd6amlg.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Agora você tem que substituir essa variável &lt;strong&gt;%USERPROFILE%&lt;/strong&gt; pelo seu caminho de usuário. Então vai ser basicamente esse:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;keytool -list -v -alias androiddebugkey -keystore C:\Users\jorge.android\debug.keystore&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Espero que tenha ajudado, valeu!&lt;/p&gt;

&lt;h2&gt;
  
  
  Referências
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://developers.google.com/android/guides/client-auth"&gt;https://developers.google.com/android/guides/client-auth&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=bi_mMQfo90s"&gt;https://www.youtube.com/watch?v=bi_mMQfo90s&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=1k-gITZA9CI&amp;amp;t=352s"&gt;https://www.youtube.com/watch?v=1k-gITZA9CI&amp;amp;t=352s&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Onboarding UI Screen em Flutter</title>
      <dc:creator>Joabe Ramone</dc:creator>
      <pubDate>Sat, 19 Jun 2021 03:41:05 +0000</pubDate>
      <link>https://forem.com/joaberamone/onboarding-ui-screen-em-flutter-4d9b</link>
      <guid>https://forem.com/joaberamone/onboarding-ui-screen-em-flutter-4d9b</guid>
      <description>&lt;p&gt;🚀Quer aprender FLUTTER do Zero ao Profissional? 👉&lt;a href="https://go.hotmart.com/O70564427D" rel="noopener noreferrer"&gt;https://go.hotmart.com/O70564427D&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  1 Introdução
&lt;/h2&gt;

&lt;p&gt;Eai clan, tudo certo?&lt;/p&gt;

&lt;p&gt;Hoje venho falar daquelas telas de abertura que sempre aparece quando acabamos de instalar um App, eu sempre confundia ela com o Splash Screen, mas tem bastante diferença. O Splash Screen acaba sendo a porta de entrada e o Onboarding é a recepção que irá orientar o usuário do App.&lt;/p&gt;

&lt;p&gt;É como na vida real. Imagine que você entra em uma loja para comprar um produto e não sabe por onde começar. Geralmente chega algum vendedor para te orientar onde fica os produtos na loja. No digital é a mesma coisa!&lt;/p&gt;

&lt;p&gt;Então vou apresentar algumas boas práticas e como pode estar implementando em Flutter com e sem biblioteca.&lt;/p&gt;

&lt;p&gt;Não esqueça de deixar sua curtida, me ajuda muito a sempre produzir conteúdo. Boa leitura!&lt;/p&gt;

&lt;h2&gt;
  
  
  2 Boas praticas UI
&lt;/h2&gt;

&lt;p&gt;Onboarding é uma experiência de desembalagem virtual que ajuda os usuários a começar a usar um aplicativo, é um conceito de embarcar ou até mesmo de se introduzir no contexto.&lt;/p&gt;

&lt;p&gt;Então temos três tipos de Onboarding para usar: a auto-seleção, início rápido e benefícios para o usuário principal.&lt;/p&gt;

&lt;h4&gt;
  
  
  2.1 Modelo de auto-seleção
&lt;/h4&gt;

&lt;p&gt;O modelo Self-Select(auto-seleção) permite que os usuários personalizem sua experiência de primeira execução, fazendo uma pequena série de escolhas.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0sty10vewxzbueky1wta.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0sty10vewxzbueky1wta.png" alt="auto-select"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As opções devem:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ser significativo e perceptível&lt;/li&gt;
&lt;li&gt;Fornecer novas informações&lt;/li&gt;
&lt;li&gt;Ser breve&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;
  
  
  Significativo e perceptível
&lt;/h5&gt;

&lt;p&gt;Nesse modelo tem opções que vão ter um impacto significativo e perceptível na experiência do usuário. Isso ensina aos usuários como interagir com sua interface.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmvr1zv2i05iro0thgo2g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmvr1zv2i05iro0thgo2g.png" alt="Nfazer"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flaha4xxdtv4zt8pk12w6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flaha4xxdtv4zt8pk12w6.png" alt="fazer"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h5&gt;
  
  
  Seja breve
&lt;/h5&gt;

&lt;p&gt;Limite as opções a uma tela ou faça com que várias telas pareçam estar conectadas umas às outras.&lt;/p&gt;

&lt;p&gt;Cada tela deve ter menos de dez opções.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcg8vi2f3oaipf6ckaiaz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcg8vi2f3oaipf6ckaiaz.png" alt="breve"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ao projetar a integração, pense em como o processo de integração se conecta à experiência de primeira execução do usuário. Após a integração, os usuários devem chegar a uma tela que facilite a ação sobre o que acabaram de aprender.&lt;/p&gt;

&lt;h4&gt;
  
  
  2.2 Modelo de início rápido
&lt;/h4&gt;

&lt;p&gt;Neste modelo os usuários acessam diretamente a interface sem nenhum modelo de integração mostrado (além de login e configuração).&lt;/p&gt;

&lt;p&gt;O modelo de início rápido:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Permite que os usuários iniciem rapidamente com a funcionalidade central do aplicativo&lt;/li&gt;
&lt;li&gt;Frequentemente prioriza a primeira ação-chave&lt;/li&gt;
&lt;li&gt;Também pode fornecer uma maneira opcional de aprender mais ou pedir ajuda&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;
  
  
  Dê aos usuários algo para fazer
&lt;/h5&gt;

&lt;p&gt;Em vez de deixar os usuários em uma tela em branco, sua interface deve encorajar a interação.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1adu5w015tdwaszdffhf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1adu5w015tdwaszdffhf.png" alt="fazer"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h5&gt;
  
  
  Priorize a primeira ação-chave
&lt;/h5&gt;

&lt;p&gt;Escolha a ação mais intimamente ligada ao engajamento nos primeiros sete dias. Como alternativa, introduza a funcionalidade principal como dicas para ações que o usuário não tentou.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F04ftys35gkk0pzyuh1df.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F04ftys35gkk0pzyuh1df.png" alt="chave"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h5&gt;
  
  
  Oferecer ajuda
&lt;/h5&gt;

&lt;p&gt;Se parecer que o usuário não tem certeza de como usar o aplicativo no final da experiência média de primeira execução (90% do caminho até a primeira sessão), exiba um SnackBar de IU oferecendo a oportunidade de aprender como usar o aplicativo.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7ri9ofep2pcq97bi50b1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7ri9ofep2pcq97bi50b1.png" alt="ajda"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  2.3 Modelo de benefícios para o usuário principal
&lt;/h4&gt;

&lt;p&gt;O modelo de integração Principais benefícios para o usuário contém um breve carrossel de reprodução automática, ou storyboard animado, que destaca os principais benefícios de usar um aplicativo.&lt;/p&gt;

&lt;h5&gt;
  
  
  Escolhendo os benefícios certos
&lt;/h5&gt;

&lt;p&gt;O modelo de Principais benefícios para o usuário deve demonstrar até três benefícios principais de usar o aplicativo. Esses benefícios devem posicionar o aplicativo como relevante e pessoal durante um momento importante, em vez de fornecer instruções ou descrever recursos.&lt;/p&gt;

&lt;p&gt;Ao identificar quais benefícios apresentar, considere:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Problemas que o aplicativo resolve&lt;/li&gt;
&lt;li&gt;Os principais benefícios que o aplicativo cria&lt;/li&gt;
&lt;li&gt;Os “recursos de escova de dentes” do aplicativo (ou seja, um recurso que você usaria uma ou duas vezes por dia)&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;
  
  
  Opções de integração
&lt;/h5&gt;

&lt;p&gt;Carrossel de rotação automática&lt;br&gt;
No máximo três ilustrações devem girar automaticamente a cada dois a três segundos e exibir a navegação de paginação. Avance automaticamente a primeira tela mais rapidamente para que fique claro que não é uma única tela. O recurso de avanço automático deve ser desativado se o usuário tocar no carrossel.&lt;/p&gt;

&lt;p&gt;Exiba um botão “Começar” em toda a animação e percorra-a continuamente até que a ação “Começar” seja tocada.&lt;/p&gt;

&lt;p&gt;A tela deve ser habilitada para deslizar, seja para frente ou para trás.&lt;/p&gt;

&lt;p&gt;VIDEO DE EXEMPLO&lt;/p&gt;

&lt;p&gt;O botão e a navegação de paginação são fixos. A tipografia é dinâmica e em um campo separado da ilustração, mas ao mesmo nível.&lt;/p&gt;
&lt;h5&gt;
  
  
  Melhores Práticas
&lt;/h5&gt;
&lt;h6&gt;
  
  
  Manter a continuidade visual
&lt;/h6&gt;

&lt;p&gt;Mantenha a continuidade visual em todos os personagens, ambientes, estilo, tipografia e cores dos botões.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7vedzfn2p70208q3jfvm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7vedzfn2p70208q3jfvm.png" alt="visual"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h6&gt;
  
  
  Simplificar
&lt;/h6&gt;

&lt;p&gt;Simplifique o visual para o essencial necessário para transmitir um conceito.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa114t8k4l0fwzn87ijke.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa114t8k4l0fwzn87ijke.png" alt="simplificar"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h6&gt;
  
  
  Não seja literal de IU
&lt;/h6&gt;

&lt;p&gt;Não mostre a IU do aplicativo se os usuários ainda não a experimentaram. Mostre o benefício do usuário primeiro.&lt;/p&gt;

&lt;p&gt;Você pode exibir informações sobre a IU específica em um contexto posterior.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjyrohe8mfgu1t7t2nh0s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjyrohe8mfgu1t7t2nh0s.png" alt="literal"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Design onboarding que se conecta a uma experiência de primeira execução. A IU vista após a integração deve tornar mais fácil para os usuários agirem de acordo com o que acabaram de aprender.&lt;/p&gt;
&lt;h3&gt;
  
  
  Projeto
&lt;/h3&gt;

&lt;p&gt;O design dos Principais benefícios para o usuário deve complementar a redação. Se houver uma ideia que pode ser melhor expressa por meio de palavras, use texto em vez de imagens.&lt;/p&gt;

&lt;p&gt;Esses layouts são projetados para permitir uma ilustração com proporção de 1: 1 para caber consistentemente em telas em todas as plataformas. Certifique-se de que o plano de fundo e a cor do texto atendam às taxas de contraste mínimas para acessibilidade.&lt;/p&gt;
&lt;h4&gt;
  
  
  Retrato de celular e tablet
&lt;/h4&gt;

&lt;p&gt;Coloque a cópia e as interações alinhadas ao centro abaixo da ilustração.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvvtxuhuohby1rlcf7nk4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvvtxuhuohby1rlcf7nk4.png" alt="alinhamento"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  Área de Trabalho
&lt;/h4&gt;

&lt;p&gt;Coloque ilustração, cópia e interações em um cartão centralizado. Exiba os botões “Próximo” e “Anterior” ao lado deste cartão e os indicadores de paginação abaixo dele.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo8gcxx0ga50ffg4xcrag.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo8gcxx0ga50ffg4xcrag.png" alt="area"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  3 Implementação
&lt;/h2&gt;

&lt;p&gt;Vamos criar um exemplo comum de onboarding, onde é apresentado quais os beneficios do aplicativo e tela de apresentação, para um restaurante entregar seus pedidos. Quando o usuário passar por essa sessão, ela não será mais apresentada para ele ao inicializar o aplicativo.&lt;/p&gt;
&lt;h4&gt;
  
  
  3.1 UI
&lt;/h4&gt;

&lt;p&gt;Eu fiz o mockup pensando nos principios do modelo de benefícios para o usuário principal, então ele tem uma figura centralizada com um título e uma breve descrição. E as ações para passar o slide ou pular a introdução.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpz23prjcy46b98pnz6xc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpz23prjcy46b98pnz6xc.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwjfhgaw2sx1btctwu5er.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwjfhgaw2sx1btctwu5er.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fev5zpcgifk3jihyz16rn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fev5zpcgifk3jihyz16rn.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  3.2 Importar bicliotecas
&lt;/h4&gt;

&lt;p&gt;No arquivo &lt;strong&gt;pubspec&lt;/strong&gt; adicione a biblioteca &lt;strong&gt;shared_preferences&lt;/strong&gt; para guardar a variavel que vai nos dizer se tem que mostrar a tela de onboarding, e importe as imagens que será utilizada.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dependencies:
  flutter:
    sdk: flutter
  shared_preferences: ^2.0.6
flutter:
  uses-material-design: true
  assets:
    - assets/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  3.2 Criar Interfaces
&lt;/h4&gt;

&lt;p&gt;Pra gente controlar o fluxo de tela, se deve ou não aparecer a sessão de onboarding. Vamos fazer uma simples verificação para saber se vamos chamar a página inicial ou a tela de onboarding.&lt;/p&gt;

&lt;p&gt;Eu criei alguns widgets para facilitar montar a interface, então dê uma olhada na pasta widgets do projeto no GitHub.&lt;/p&gt;

&lt;p&gt;Então o primeiro passo é:&lt;/p&gt;

&lt;p&gt;1 - Criar a função que vai fazer verificação se o usuário já passou pela onboarding, na classe Main;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
_initAppVerificaSeEstaAtivo() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    final ativo = prefs.getBool(_ativoVar) ?? false;

    setState(() {
      _ativo = ativo;
    });
  }

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;2 - Criar as telas HomeScreen e OnboardingScreen e adicionar a essa verificação na Main;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
_ativo ? HomeScreen() : OnboardingScreen(),

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;3 - Na tela OnboardingScreen vamos criar as variaveis;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
final PageController _pageController = PageController(initialPage: 0);
int _currentPage = 0;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;4 - criar a função responsável por setar nossa variável para ativar ou desativar o onboarding;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  _setEstado() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    bool ativo = prefs.getBool('ativo') ?? false;

    if (!ativo) {
      await prefs.setBool('ativo', true);
    }
  }

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;5 - depois a função de dar next da PageView;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  void proximoCard() {
    _pageController.nextPage(
        duration: Duration(seconds: 1), curve: Curves.easeIn);
  }

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;6 - depois a função que vai redirecionar para tela inicial e chamar a função _setEstado().&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
  void irParaPaginaInicial() {
    Navigator.pushReplacement(
        context, MaterialPageRoute(builder: (context) =&amp;gt; HomeScreen()));

    _setEstado();
  }


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;7 - a estrutura base da tela vai ser essa;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Color(0xFFFFF7CD),
      body: SafeArea(
        child: Stack(children: [

          //Adicionar os elementos aqui

        ]),
      ),
    );
  }

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;8 - as figuras;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PageView(
            controller: _pageController,
            onPageChanged: (int page) {
              setState(() {
                _currentPage = page;
              });
            },
            physics: ClampingScrollPhysics(),
            children: [
              CustomSlider(
                imagem: 'assets/onboarding-image-1.png',
                titulo: 'Sua Comida favorita',
                texto:
                    'Almoço, janta, cafézinho da manhã ou da tarde. A qual quer horário para atendimento.',
                acaoBotao: 'CONTINUAR',
              ),
              CustomSlider(
                imagem: 'assets/onboarding-image-2.png',
                titulo: 'Você recebe no conforto de onde estiver',
                texto:
                    'Seu pedido é atendido pelo restaurante mais próximo, que leva tudo pra você.',
                acaoBotao: 'CONTINUAR',
              ),
              CustomSlider(
                imagem: 'assets/onboarding-image-3.png',
                titulo: 'Melhores Chef’s',
                texto:
                    'Chefs, dos quais a maioria vem de restaurantes com estrelas Michelin ou são vencedores de competições de prestígio e títulos.',
                acaoBotao: 'CONTINUAR',
              ),
            ],
          ),
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;9 - o botão de &lt;strong&gt;continuar&lt;/strong&gt; muda quando para &lt;strong&gt;quero conhecer&lt;/strong&gt; quando for a última figura e muda a ação do botão também;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
Padding(
            padding: const EdgeInsets.only(bottom: 100.0),
            child: Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                CustomButton(
                  titulo: _currentPage == 2 ? 'QUERO CONHECER' : 'CONTINUAR',
                  irParaPaginaInicial:
                      _currentPage == 2 ? irParaPaginaInicial : proximoCard,
                ),
              ],
            ),
          ),

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;10 - adicionar o botão de pular a introdução;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
Padding(
            padding: const EdgeInsets.only(bottom: 50.0),
            child: Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                CustomLink(
                  titulo: 'Pular introdução',
                  irParaPaginaInicial: irParaPaginaInicial,
                )
              ],
            ),
          ),

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;11 - adicinar a paginação que vai indicar em qual das figuras está;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
Padding(
            padding: const EdgeInsets.only(bottom: 170.0),
            child: Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                CustomPaginator(
                  page: _currentPage,
                )
              ],
            ),
          ),

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🚀Quer aprender FLUTTER do Zero ao Profissional? 👉&lt;a href="https://go.hotmart.com/O70564427D" rel="noopener noreferrer"&gt;https://go.hotmart.com/O70564427D&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;💥Livros que eu indico &lt;br&gt;
Boas Práticas em Ux Design: &lt;a href="https://amzn.to/3FQ5SFP" rel="noopener noreferrer"&gt;https://amzn.to/3FQ5SFP&lt;/a&gt;&lt;br&gt;
O design do dia a dia: &lt;a href="https://amzn.to/3M5bEW5" rel="noopener noreferrer"&gt;https://amzn.to/3M5bEW5&lt;/a&gt;&lt;br&gt;
Design Centrado no Usuário: &lt;a href="https://amzn.to/3N8CEV2" rel="noopener noreferrer"&gt;https://amzn.to/3N8CEV2&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Código limpo: &lt;a href="https://amzn.to/3FIXCaw" rel="noopener noreferrer"&gt;https://amzn.to/3FIXCaw&lt;/a&gt;&lt;br&gt;
Arquitetura Limpa: &lt;a href="https://amzn.to/3FDrXHa" rel="noopener noreferrer"&gt;https://amzn.to/3FDrXHa&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Iniciando com Flutter Framework: &lt;a href="https://amzn.to/3L4I4yR" rel="noopener noreferrer"&gt;https://amzn.to/3L4I4yR&lt;/a&gt;&lt;br&gt;
Aprofundando em Flutter: &lt;a href="https://amzn.to/39c62uT" rel="noopener noreferrer"&gt;https://amzn.to/39c62uT&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Referências
&lt;/h3&gt;

&lt;p&gt;Projeto no GitHub: &lt;a href="https://github.com/JoabeRamone/onboarding-app" rel="noopener noreferrer"&gt;https://github.com/JoabeRamone/onboarding-app&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://bashooka.com/inspiration/mobile-app-onboarding-ui-examples/" rel="noopener noreferrer"&gt;https://bashooka.com/inspiration/mobile-app-onboarding-ui-examples/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://icons8.com/articles/ux-design-onboarding-mobile-app/" rel="noopener noreferrer"&gt;https://icons8.com/articles/ux-design-onboarding-mobile-app/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=YEJPg2jwzI8&amp;amp;ab_channel=TheFlutterWay" rel="noopener noreferrer"&gt;https://www.youtube.com/watch?v=YEJPg2jwzI8&amp;amp;ab_channel=TheFlutterWay&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://material.io/design/communication/onboarding.html#usage" rel="noopener noreferrer"&gt;https://material.io/design/communication/onboarding.html#usage&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dribbble.com/shots/14479371-Onboarding-Screen-Exploration" rel="noopener noreferrer"&gt;https://dribbble.com/shots/14479371-Onboarding-Screen-Exploration&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=CQlA2p--oEg&amp;amp;ab_channel=JohannesMilke" rel="noopener noreferrer"&gt;https://www.youtube.com/watch?v=CQlA2p--oEg&amp;amp;ab_channel=JohannesMilke&lt;/a&gt;&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>android</category>
      <category>onboarding</category>
      <category>mobile</category>
    </item>
    <item>
      <title>Traduzir seu App em Flutter</title>
      <dc:creator>Joabe Ramone</dc:creator>
      <pubDate>Sat, 13 Mar 2021 18:13:46 +0000</pubDate>
      <link>https://forem.com/joaberamone/traduzir-seu-app-em-flutter-5cbf</link>
      <guid>https://forem.com/joaberamone/traduzir-seu-app-em-flutter-5cbf</guid>
      <description>&lt;h2&gt;
  
  
  1 Introdução
&lt;/h2&gt;

&lt;p&gt;Hey clan, all right?&lt;br&gt;
Eai clan, tudo certo?&lt;/p&gt;

&lt;p&gt;Hoje eu venho falar sobre tradução, como deixar seu app flutter em vários idiomas. Afinal, queremos deixar nosso app mais acessível possível né? Haha'&lt;/p&gt;

&lt;p&gt;E pra isso vamos falar de flutter localizations.&lt;/p&gt;
&lt;h2&gt;
  
  
  2 Localizações em Flutter
&lt;/h2&gt;

&lt;p&gt;Por padrão, o Flutter fornece apenas localizações em inglês dos Estados Unidos. Para adicionar suporte a outros idiomas seu app deve especificar propriedades adicionais no MaterialApp (ou CupertinoApp) e incluir um pacote chamado &lt;strong&gt;flutter_localizations&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;Então, o primeiro passo é adicionar o pacote como uma dependência ao seu arquivo &lt;strong&gt;pubspec.yaml&lt;/strong&gt; do seu projeto.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dependencies:
  flutter:
    sdk: flutter
  flutter_localizations: # Coloque essa linha
    sdk: flutter         # e essa
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Em seguida execute &lt;strong&gt;pub get packages&lt;/strong&gt;, importe a biblioteca &lt;strong&gt;flutter_localizations&lt;/strong&gt; e coloque &lt;strong&gt;localizationsDelegates&lt;/strong&gt; e &lt;strong&gt;supportedLocales&lt;/strong&gt; no &lt;strong&gt;MaterialApp&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import 'package:flutter_localizations/flutter_localizations.dart';
// TODO: descomente a linha abaixo após codegen
// import 'package:flutter_gen/gen_l10n/app_localizations.dart';

// ...

MaterialApp(
 localizationsDelegates: [
   // TODO: descomente a linha abaixo após codegen
   // AppLocalizations.delegate,
   GlobalMaterialLocalizations.delegate,
   GlobalWidgetsLocalizations.delegate,
   GlobalCupertinoLocalizations.delegate,
 ],
 supportedLocales: [
    const Locale('en', ''), // Inglês
    const Locale('pt', ''), // Português
    const Locale.fromSubtags(languageCode: 'zh'), // Chinês *Veja os locais avançados abaixo *
    // ... outras localidades que o aplicativo suporta
  ],
  // ...
)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Depois de introduzir o pacote &lt;strong&gt;flutter_localizations&lt;/strong&gt; e adicionar o código acima, você pode escolher a ordem de tradução. No caso do código a cima o inglês está em primeiro lugar e isso quer dizer que quando for outro idioma que não tenha na lista &lt;strong&gt;localizationsDelegates&lt;/strong&gt; o app vai deixar em inglês. Os widgets devem ser adaptados às mensagens localizadas, juntamente com o layout correto da esquerda para a direita e da direita para a esquerda.&lt;/p&gt;

&lt;p&gt;Os elementos da lista &lt;strong&gt;localizationsDelegates&lt;/strong&gt; são fábricas que produzem coleções de valores localizados.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GlobalMaterialLocalizations.delegate&lt;/strong&gt; fornece strings localizadas e outros valores para a biblioteca de componentes de materiais. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GlobalWidgetsLocalizations.delegate&lt;/strong&gt; define a direção do texto padrão, da esquerda para a direita ou da direita para a esquerda, para a biblioteca de widgets.&lt;/p&gt;

&lt;h2&gt;
  
  
  3 Traduzir os textos do seu App
&lt;/h2&gt;

&lt;p&gt;Depois que adicionou o pacote &lt;strong&gt;flutter_localizations&lt;/strong&gt; vamos seguir as seguintes etapas:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1&lt;/strong&gt;  Adicionar o pacote &lt;strong&gt;intl&lt;/strong&gt; no &lt;strong&gt;pubspec.yaml&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dependencies:
  flutter:
    sdk: flutter
  flutter_localizations:
    sdk: flutter
  intl: ^0.17.0    # Adicionar essa linha
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Esse pacote fornece recursos de internacionalização e localização, incluindo tradução de mensagens, plurais e gêneros, formatação e análise de data/número e texto bidirecional.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Dica: sempre verifique se existe atualização quando adicionar um pacote. (&lt;a href="https://pub.dev/" rel="noopener noreferrer"&gt;pub.dev&lt;/a&gt;)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;2&lt;/strong&gt;  Habilite o sinalizador de geração no &lt;strong&gt;pubspec.yaml&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# A seção a seguir é específica para Flutter.
flutter:
  generate: true    # Adicione essa linha
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3&lt;/strong&gt;  Adicione um novo arquivo &lt;strong&gt;yaml&lt;/strong&gt; ao diretório raiz do seu projeto chamado de &lt;strong&gt;l10n.yaml&lt;/strong&gt; com o seguinte conteúdo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;arb-dir: lib/l10n 
template-arb-file: app_en.arb
output-localization-file: app_localizations.dart
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo9xpw01tc4atyzed1xzt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo9xpw01tc4atyzed1xzt.png" alt="Arquivo l10n"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Este arquivo configura a ferramenta de localização, isso significa que na:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Primeira linha: é caminho do arquivo de entrada que vai estar em ${PROJETO_FLUTTER}/lib/l10n,mas não criamos essa pasta ainda.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Segunda linha: é a tradução base dos textos no formato &lt;a href="https://pt.stackoverflow.com/questions/4042/o-que-%C3%A9-json-para-que-serve-e-como-funciona" rel="noopener noreferrer"&gt;JSON&lt;/a&gt; que vamos colocar, no caso está o arquivo &lt;strong&gt;app_en.arb&lt;/strong&gt; que é o de inglês.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Esse arquivo é o principal, então você tem que colocar tudo em inglês primeiro para criar um chave em cada texto.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Terceira linha: é o arquivo onde as localizações são geradas.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;4&lt;/strong&gt;  Crie uma pasta com o nome &lt;strong&gt;l10n&lt;/strong&gt; dentro da pasta &lt;strong&gt;lib&lt;/strong&gt; e também crie um arquivo com o nome &lt;strong&gt;app_en.arb&lt;/strong&gt;, dentro desse arquivo adicione esse conteúdo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "helloWorld": "Hello World!"
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;5&lt;/strong&gt;  Agora, crie outro arquivo com o nome de app_pt.arb no mesmo diretório e traduz somente o valor de helloWorld.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "helloWorld": "Óla Mundo!"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Dica: as chaves tem que ser iguais em todos os arquivos.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj4etlirkylnzhs16wofr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj4etlirkylnzhs16wofr.png" alt="pasta l10n"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6&lt;/strong&gt;  Agora você tem que executar seu projeto para que aconteça o &lt;strong&gt;codegen&lt;/strong&gt; e depois disso você consegue ver os arquivos gerados no caminho: &lt;code&gt;${FLUTTER_PROJECT}/.dart_tool/flutter_gen/gen_l10n.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;7&lt;/strong&gt; Já podemos remover aquele código comentado na nossa main dentro do MaterialApp e atualizar nosso projeto que já irá funcionar.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import 'package:flutter_localizations/flutter_localizations.dart';
// import 'package:flutter_gen/gen_l10n/app_localizations.dart'; // remova este comentario

// ...

MaterialApp(
  localizationsDelegates: [
    // AppLocalizations.delegate, // remova este comentario
    GlobalMaterialLocalizations.delegate,
    // ...
);

// Use AppLocalizations em qualquer lugar em seu aplicativo.
// Aqui, a mensagem traduzida é usada em um widget de texto
Widget build(BuildContext context) {
  // ...
  return Text(AppLocalizations.of(context).helloWorld);
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Este código &lt;code&gt;Text(AppLocalizations.of(context).helloWorld)&lt;/code&gt; gera um widget de texto que exibe “Hello World!”.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fth7jj9z4hw20bj3bbvi4.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fth7jj9z4hw20bj3bbvi4.jpg" alt="Exemplo ola mundo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Caso você mudar o idioma do seu dispositivo para qual quer outro, neste exemplo de código vai ficar em inglês.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fizhjn6hx0pfgmlhvnyf2.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fizhjn6hx0pfgmlhvnyf2.jpg" alt="Exemplo hello world"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Dica: Nos arquivos &lt;strong&gt;.arb&lt;/strong&gt;, a chave de cada entrada é usada como o nome do método do getter, enquanto o valor dessa entrada contém a mensagem localizada.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Você pode adicionar o plugin do *&lt;em&gt;intl&lt;/em&gt; também.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcikbhc7c21mtapxx53tf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcikbhc7c21mtapxx53tf.png" alt="Plugin"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  4 Conclusão
&lt;/h2&gt;

&lt;p&gt;Muito simples né? &lt;/p&gt;

&lt;p&gt;Agora você pode colocar seu app em vários idiomas e fazer sucesso no mundo todo. :D&lt;/p&gt;

&lt;p&gt;Espero que tenha te ajudado em algo, deixe seu like e compartilhe para os amigos. Vamos sempre estar contribuindo para nossa comunidade dev! &lt;/p&gt;

&lt;p&gt;Valeu, é nóis!&lt;/p&gt;

&lt;h2&gt;
  
  
  5 Referencias:
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://flutter.dev/docs/development/accessibility-and-localization/internationalization" rel="noopener noreferrer"&gt;Documentação do Flutter&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://pub.dev/packages/intl" rel="noopener noreferrer"&gt;Pacote intl&lt;/a&gt;&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>android</category>
      <category>code</category>
      <category>traduzir</category>
    </item>
    <item>
      <title>Splash Screen UI em Flutter</title>
      <dc:creator>Joabe Ramone</dc:creator>
      <pubDate>Sat, 27 Feb 2021 03:20:55 +0000</pubDate>
      <link>https://forem.com/joaberamone/splash-screen-ui-em-flutter-12g4</link>
      <guid>https://forem.com/joaberamone/splash-screen-ui-em-flutter-12g4</guid>
      <description>&lt;h2&gt;
  
  
  1. Introdução
&lt;/h2&gt;

&lt;p&gt;Eai clan, tudo certo? &lt;/p&gt;

&lt;p&gt;Hoje venho falar sobre um conteúdo que muita das vezes passa despercebido mas que faz muito diferença, por que ele é a porta de entrada para os usuários dos nossos aplicativos. Eu fiz várias pesquisas sobre as boas práticas seguindo os fundamentos de design.&lt;/p&gt;

&lt;p&gt;O termo &lt;em&gt;Splash Screen&lt;/em&gt; traduzido significa tela inicial e surgiu da necessidade dos aplicativos carregarem todas as informações antes que o usuário pudesse acessa-lo.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fypnwzxncxatz9l2xmxty.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fypnwzxncxatz9l2xmxty.png" alt="Exemplo de Splash screen"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Quase sempre há algumas pequenas tarefas que o seu aplicativo precisa fazer antes que o usuário possa começar a tocar nos botões e navegar nas telas. Talvez seu aplicativo precise carregar alguns dados básicos para carregar a primeira tela ou o usuário precise ser autenticado novamente porque não usa o aplicativo há algum tempo. Seja o que for, a tela inicial é o lugar perfeito para fazer isso (bem ... na maioria das vezes).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvshcba0pi7k6vo8hpxg2.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvshcba0pi7k6vo8hpxg2.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
&lt;code&gt;Carregamento dos dados&lt;/code&gt;   &lt;/p&gt;
&lt;h2&gt;
  
  
  2. Boas práticas do uso
&lt;/h2&gt;

&lt;p&gt;Existem algumas funcionalidades chave que seu aplicativo deve ter, embora você possa não ver essas funcionalidades em ação elas estão escondidas sob a superfície na maioria das telas iniciais que você vê no seu celular. Qualquer usuário que usa seu aplicativo regularmente ficará rapidamente frustrado se tiver que sentar e esperar que um aplicativo seja aberto por mais de alguns segundos. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F86pu3bgncrcuzwnyyi07.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F86pu3bgncrcuzwnyyi07.png" alt="exemplo de demora"&gt;&lt;/a&gt;&lt;br&gt;
&lt;code&gt;Ninguém gosta de esperar né?! Imagina o app demorar abrir pra &lt;br&gt;
 você falar com seu crush, TENSO NÉ haha&lt;/code&gt; &lt;/p&gt;
&lt;h3&gt;
  
  
  2.1 Três Segundos é o suficiente
&lt;/h3&gt;

&lt;p&gt;Em primeiro lugar, a tela inicial deve ser rápida. Nunca mais do que 2 ou 3 segundos. Leve em consideração que se o seu aplicativo estiver sendo usado regularmente, você deve reduzir isso para 1 segundo ou até mesmo tentar remover a necessidade de uma tela inicial.&lt;/p&gt;

&lt;p&gt;Imagine ter que esperar a tela de abertura do Whatsapp de 3 segundos toda vez que quiser enviar uma mensagem para um amigo. Nesses casos, você pode pular o Splash Screen completamente e ir direto para o conteúdo carregando tudo o que você precisa da tela principal e exibindo quaisquer erros ou problemas depois de carregados.&lt;/p&gt;

&lt;p&gt;Então certifique-se de que se ela quebrar a regra dos 3 segundos invente uma nova estratégia.&lt;/p&gt;
&lt;h3&gt;
  
  
  2.2 Porta de entrada
&lt;/h3&gt;

&lt;p&gt;Provavelmente você já viu que hotéis e grandes empresas gastam muito dinheiro em suas entradas grandiosas e impressionantes, isso é porque no momento em que você passa por aquela porta você sabe que está em um lugar de qualidade. O mesmo se aplica a aplicativos, no momento em que um usuário toca em seu ícone na tela inicial eles são transportados para o seu mundo. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F92y36bxhtlteejome6wv.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F92y36bxhtlteejome6wv.jpg" alt="motel"&gt;&lt;/a&gt;&lt;br&gt;
&lt;code&gt;Entrada do Motel Egytus&lt;/code&gt;  &lt;/p&gt;

&lt;p&gt;Então mantenha o design simples , ousado e visual. Naqueles preciosos 3 segundos, o usuário não tem tempo para digerir várias informações, então concentre-se em apresentar o aplicativo pela primeira vez de uma forma visualmente atraente.&lt;/p&gt;

&lt;p&gt;As telas iniciais mais simples mostrarão um &lt;strong&gt;fundo sólido&lt;/strong&gt; ou &lt;strong&gt;gradiente&lt;/strong&gt; com o ícone do aplicativo e o &lt;strong&gt;título desaparecendo&lt;/strong&gt; a vista. Dê um passo adiante e anime o ícone do seu aplicativo para dar uma sensação real de qualidade mas apenas lembre-se de manter a animação focada e simples e definitivamente &lt;strong&gt;não quebre a regra dos 3 segundos&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F11epmg9ky2we6q8ev2mb.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F11epmg9ky2we6q8ev2mb.gif" alt="Uber"&gt;&lt;/a&gt;&lt;br&gt;
&lt;code&gt;O Uber manteve a simplicidade, mas com uma animação muito boa para mergulhar você na experiência do aplicativo.&lt;/code&gt;  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpam4sdxjhk8wjimfn7eo.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpam4sdxjhk8wjimfn7eo.gif" alt="taxi"&gt;&lt;/a&gt;&lt;br&gt;
&lt;code&gt;Outro exemplo de simples e ousado.&lt;/code&gt;   &lt;/p&gt;

&lt;p&gt;Sobre animações, não leve isso muito a sério. Alguns designers têm o hábito de exagerar e criar uma animação que conta uma grande história. O que é ótimo se o ícone do seu aplicativo tem uma história para contar. Mas lembre-se, além da primeira vez que o usuário vê isso, não fará diferença a história que você contar. Portanto, mantenha-o simples e se você realmente quiser enlouquecer peça aos seus desenvolvedores para programá-lo de forma que só mostre a animação complexa na primeira vez que o usuário abrir o aplicativo, com uma alternativa mais simples e leve para as sessões subsequentes. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3x9hw4pxi52jb1h8hw7r.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3x9hw4pxi52jb1h8hw7r.gif" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
&lt;code&gt;A abertura pode ser muito longo para cada sessão.&lt;/code&gt;   &lt;/p&gt;

&lt;p&gt;E quando tiver orçamento, tempo e habilidades suficientes, você pode ir mais longe integrando sua tela inicial perfeitamente ao resto de sua experiência de usuário. A estratégia geral é projetar o plano de fundo de sua tela inicial de modo que possa se mesclar facilmente com a primeira tela de seu aplicativo.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7f9ya08jfg639j3r0tru.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7f9ya08jfg639j3r0tru.gif" alt="shazam app"&gt;&lt;/a&gt;&lt;br&gt;
&lt;code&gt;Shazam integra seu logotipo em sua interface principal perfeitamente.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Não é uma tarefa fácil, por que esse tipo de transição só funciona com determinados aplicativos e principalmente aqueles em que o logotipo principal aparece na tela ou a tela principal do aplicativo é uma única tela com conteúdo relativamente mínimo nele.&lt;/p&gt;
&lt;h3&gt;
  
  
  2.3 Se o carregamento violar a regra dos 3 segundos
&lt;/h3&gt;

&lt;p&gt;Claro que pode acontecer de demorar mais que 3 segundos para carregar, isso não quer dizer que seu aplicativo tenha que carregar muitos dados, mas mesmo com dados mínimos, o dispositivo pode ter uma conectividade com a Internet muito lenta e até mesmo uma única imagem pode levar mais do que alguns segundos para carregar. Nesse caso, você vai precisar usar um indicador de carregamento pode ser uma pequena roda giratória ou barra de progresso para manter seus usuários informados de que o aplicativo está fazendo algo.&lt;/p&gt;

&lt;p&gt;Um truque incrível é mostrar o indicador de carregamento apenas após o término da animação inicial. Dessa forma, o usuário normalmente nunca o verá, mas se vir, saberá que o aplicativo ainda está funcionando e terá que esperar pacientemente até que seja concluído. Alguns aplicativos repetem sua animação inicial - mas isso não informa ao usuário que o aplicativo precisa de mais tempo, e então eles ficarão com a sensação de que você está apenas perdendo seu tempo com uma animação repetida. Portanto, faça o que fizer, mostre o indicador de carregamento assim que passar 3 segundos.&lt;/p&gt;

&lt;p&gt;Para conteúdo que geralmente é diferente toda vez que um usuário entra em um aplicativo, por exemplo um aplicativo bancário, significa que o splash sempre será "lento", porque toda vez que você abrir o aplicativo ele vai precisar carregar novos dados. Nesses casos, é melhor você direcionar seus usuários para o conteúdo e carregar bem diante de seus olhos para que o tempo de carregamento seja dividido em duas partes. É um equilíbrio complicado de acertar, então certifique-se de fazer testes em seus aplicativos com uma conexão lenta para ter uma ideia de quanto tempo dura quando as pessoas estão usando seu aplicativo.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftrjdnwuv55jwwn13xlb2.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftrjdnwuv55jwwn13xlb2.gif" alt="duas etapas"&gt;&lt;/a&gt;&lt;br&gt;
&lt;code&gt;NuBank mostrando as duas etapas de inicialização.&lt;/code&gt;  &lt;/p&gt;
&lt;h3&gt;
  
  
  2.4 Erro ao carregar o app
&lt;/h3&gt;

&lt;p&gt;Embora a maioria dos erros em um aplicativo possa ser tratada com um pop-up, apresentar um pop-up na tela inicial será desagradável e frustrante para o usuário. A melhor estratégia que você pode ter aqui é isolar apenas os erros críticos. Se uma imagem está demorando muito para carregar você não precisa atrasar o usuário, você pode ignorar este erro e tentar recarregá-la na próxima tela. Mas se a conexão com a Internet estiver desligada e você não conseguir autenticar seu usuário, você realmente não pode permitir que ele passe por essa tela. Portanto, primeiro certifique-se de apresentar um erro apenas se o problema for crítico o suficiente para que o usuário não deva continuar usando o aplicativo.&lt;/p&gt;

&lt;p&gt;Imagine um aplicativo que logo após o término da animação inicial apresenta um pop-up feio para dizer que você não tem conexão com a internet, nem elegante nem sofisticado. Em vez disso, por que não integrar o erro em sua tela inicial. Quase sempre optamos por uma mensagem de erro na própria tela inicial junto com um botão de atualização e a maioria dos casos o problema será uma simples falta de internet e portanto um botão de atualização ou atualização automática quando a conexão retorna se torna a melhor opção. Ao manter o erro integrado nesta tela você mantém uma aparência profissional no aplicativo enquanto também avisa claramente o usuário para tocar no botão de atualização.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fudfr0er1y7urkfcjdj28.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fudfr0er1y7urkfcjdj28.gif" alt="exemplo de erro"&gt;&lt;/a&gt;&lt;br&gt;
&lt;code&gt;NuBanck mostra erro de conexão diretamente na tela inicial para evitar pop-ups&lt;/code&gt;  &lt;/p&gt;
&lt;h3&gt;
  
  
  2.5 Para concluir
&lt;/h3&gt;

&lt;p&gt;Então lembre-se:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Mantenha a simplicidade com uma animação curta e elegante para apresentar seu aplicativo&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Lembre-se sempre da regra dos 3 segundos e se passar mais que isso mostre um indicador de carregamento.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Carregue os dados mínimos absolutos do servidor, mas certifique-se de ter todas as informações necessárias para mostrar a próxima tela imediatamente.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Integre erros em sua tela inicial para evitar popups feios. &lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  3. Como fazer em Flutter
&lt;/h2&gt;

&lt;p&gt;O que é maravilhoso em Flutter é que ele já tem uma Splash Screen nativo, provavelmente se você já rodou algum projeto do Flutter deve ter visto aquela tela branca ou preta aparecendo antes de abrir seu aplicativo. Então, é apenas modificar um arquivo colocando sua logo e a cor primária do seu app.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2fxois75qwlbbkx89g5h.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2fxois75qwlbbkx89g5h.jpg" alt="Só isso meme"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Basicamente sim!&lt;/p&gt;

&lt;p&gt;Cada aplicativo Android requer tempo de inicialização enquanto o sistema operacional configura o processo do aplicativo. O Android fornece o conceito de uma Splash Screen para ser exibido um Drawable durante a inicialização do aplicativo.&lt;/p&gt;
&lt;h3&gt;
  
  
  3.1 O que é Drawable
&lt;/h3&gt;

&lt;p&gt;Quando você precisa exibir imagens estáticas no seu app, é possível usar a classe Drawable e as subclasses relacionadas para desenhar formas e imagens. Um Drawable é uma abstração geral para algo que pode ser desenhado.&lt;/p&gt;

&lt;p&gt;É possível adicionar gráficos ao app referenciando um arquivo de imagem dos recursos do projeto. Os tipos de arquivo compatíveis são PNG (preferencial), JPG (aceitável) e GIF (não recomendado). Ícones do app, logotipos e outros elementos gráficos, como aqueles usados em jogos, são adequados para essa técnica.&lt;/p&gt;

&lt;p&gt;Para usar um recurso de imagem, adicione seu arquivo ao diretório res/drawable/ do projeto. Quando você estiver no projeto, poderá referenciar o recurso de imagem do seu código ou layout XML.  Por exemplo, consulte my_image.png como my_image.&lt;/p&gt;
&lt;h3&gt;
  
  
  3.2 Modificar Splash Screen
&lt;/h3&gt;

&lt;p&gt;Vamos seguir os seguintes passos:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Vá até android/app/src/main/res/drawable,&lt;/li&gt;
&lt;li&gt;abra o arquivo launch_background.xml,&lt;/li&gt;
&lt;li&gt;tire o comentário das linhas 6 e 11,&lt;/li&gt;
&lt;li&gt;abra a pasta mipmap &lt;/li&gt;
&lt;li&gt;copie o nome da imagem que estiver lá dentro,&lt;/li&gt;
&lt;li&gt;e coloque no android:src o nome da pasta e da imagem.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy9dh4ro4s0a74iyrtrrd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy9dh4ro4s0a74iyrtrrd.png" alt="adicionar icone"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Pronto! &lt;/p&gt;

&lt;p&gt;Já temos um resultado como este:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fis842wh2wepeh011t3rj.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fis842wh2wepeh011t3rj.gif" alt="Exemplo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxg4czpfrlwghhjq02bjs.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxg4czpfrlwghhjq02bjs.gif" alt="not bad"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Caso não aparecer nada veja se no seu projeto tem outra pasta com o nome &lt;strong&gt;drawable&lt;/strong&gt; pode ter outra como por exemplo &lt;strong&gt;drawable-v21&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Isso acontece por causa da sua necessidade, para imagens, você pode projetá-las para a resolução mais alta e colocá-las na pasta xxxhdpi. O Android reduzirá automaticamente a resolução para outros dispositivos. Além disso, você pode colocar drawables diferentes para resoluções diferentes. Mas eles devem ter o mesmo nome. Como por exemplo as pastas mipmap.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6i8u5oqvqwcmyzpmp3bs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6i8u5oqvqwcmyzpmp3bs.png" alt="drawable-2"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Então a pasta &lt;strong&gt;drawable-v21&lt;/strong&gt; vai ter o mesmo conteúdo que a &lt;strong&gt;drawable&lt;/strong&gt;, se preferir.&lt;/p&gt;
&lt;h3&gt;
  
  
  3.3 Adicionar cores de fundo
&lt;/h3&gt;

&lt;p&gt;Você pode mudar o fundo da Splash Screen de acordo com a cor principal do seu aplicativo, para colocar as cores do seu gosto é da seguinte maneira:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Vá até a pasta android/app/src/main/res/values&lt;/li&gt;
&lt;li&gt;crie um arquivo chamado &lt;strong&gt;colors.xml&lt;/strong&gt;,&lt;/li&gt;
&lt;li&gt;adicione as cores em HEX e coloque um nome para cada cor.
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;
&amp;lt;resources&amp;gt;
    &amp;lt;color name="red"&amp;gt;#F44336&amp;lt;/color&amp;gt;
    &amp;lt;color name="white"&amp;gt;#FFFFFF&amp;lt;/color&amp;gt;
    &amp;lt;color name="yellow"&amp;gt;#FFFF00&amp;lt;/color&amp;gt;
    &amp;lt;color name="blueGrey"&amp;gt;#37474F&amp;lt;/color&amp;gt;
    &amp;lt;color name="NightBlue"&amp;gt;#233446&amp;lt;/color&amp;gt;
    &amp;lt;color name="grey"&amp;gt;#212121&amp;lt;/color&amp;gt;
    &amp;lt;color name="dark"&amp;gt;#000000&amp;lt;/color&amp;gt;
&amp;lt;/resources&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Agora você pode usar essa cor no seu drawable da seguinte forma:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;item android:drawable="@color/red" /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3.3 Tema escuro
&lt;/h3&gt;

&lt;p&gt;Por padrão o Flutter cria uma configuração que deixa o fundo do nosso aplicativo de acordo com sistema operacional. Por exemplo, se você estiver com o tema escuro ativo quando você inicializar o aplicativo ele vai mostrar um fundo preto. E caso o tema escuro estiver Desativado ele mostra um fundo branco.&lt;/p&gt;

&lt;p&gt;Mas precisamos criar um arquivo para configurar nossa Splash Screen em tema escuro.&lt;/p&gt;

&lt;p&gt;Pra gente conseguir ver a diferença na prática vamos adicionar duas imagens de um icone do android.&lt;/p&gt;

&lt;p&gt;Então:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Vá até android/app/src/main/res&lt;/li&gt;
&lt;li&gt;crie uma pasta chamada &lt;strong&gt;drawable-night&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;coloque a imagem do android branco,&lt;/li&gt;
&lt;li&gt;crie um arquivo &lt;strong&gt;launch_background.xml&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkj53e3la8p5kf8j6140k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkj53e3la8p5kf8j6140k.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Drawable
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw9xrnnjg8vq4rwmv6l1o.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw9xrnnjg8vq4rwmv6l1o.jpg" alt="light"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;
&amp;lt;layer-list xmlns:android="http://schemas.android.com/apk/res/android"&amp;gt;
    &amp;lt;item android:drawable="@color/white" /&amp;gt;
     &amp;lt;item&amp;gt;
        &amp;lt;bitmap
            android:gravity="center"
            android:src="@drawable/android" /&amp;gt;
    &amp;lt;/item&amp;gt;
&amp;lt;/layer-list&amp;gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Arquivo: values/styles.xml&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;
&amp;lt;resources&amp;gt;
    &amp;lt;style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar"&amp;gt;
        &amp;lt;item name="android:windowBackground"&amp;gt;@drawable/launch_background&amp;lt;/item&amp;gt;
    &amp;lt;/style&amp;gt;
&amp;lt;/resources&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Drawable Night
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx9tq17h903z1fv9bh5lt.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx9tq17h903z1fv9bh5lt.jpg" alt="night"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;
&amp;lt;layer-list xmlns:android="http://schemas.android.com/apk/res/android"&amp;gt;
    &amp;lt;item android:drawable="@color/dark" /&amp;gt;
    &amp;lt;item&amp;gt;
        &amp;lt;bitmap
            android:gravity="center"
            android:src="@drawable/android" /&amp;gt;
    &amp;lt;/item&amp;gt;
&amp;lt;/layer-list&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Arquivo: values-night/styles.xml&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;
&amp;lt;resources&amp;gt;
    &amp;lt;style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar"&amp;gt;
        &amp;lt;item name="android:windowBackground"&amp;gt;@drawable/launch_background&amp;lt;/item&amp;gt;
    &amp;lt;/style&amp;gt;
&amp;lt;/resources&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  5 Conclusão
&lt;/h3&gt;

&lt;p&gt;Uma tela de carregamento pode parecer algo simples, mas como vimos tem muito fundamento. Espero que este post possa ter te ajudado de alguma forma, não esqueça de dar like para me ajudar a continuar postando. &lt;/p&gt;

&lt;p&gt;Valeu clan!&lt;/p&gt;

&lt;h3&gt;
  
  
  6 Referências
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://pub.dev/packages/flutter_native_splash/install" rel="noopener noreferrer"&gt;https://pub.dev/packages/flutter_native_splash/install&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=8ME8Czqc-Oc&amp;amp;ab_channel=JohannesMilke" rel="noopener noreferrer"&gt;https://www.youtube.com/watch?v=8ME8Czqc-Oc&amp;amp;ab_channel=JohannesMilke&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://uxdesign.cc/building-the-perfect-splash-screen-46e080395f06" rel="noopener noreferrer"&gt;https://uxdesign.cc/building-the-perfect-splash-screen-46e080395f06&lt;/a&gt;&lt;br&gt;
&lt;a href="https://dribbble.com/tags/splash_screen" rel="noopener noreferrer"&gt;https://dribbble.com/tags/splash_screen&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://flutter.dev/docs/development/ui/advanced/splash-screen" rel="noopener noreferrer"&gt;https://flutter.dev/docs/development/ui/advanced/splash-screen&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developer.android.com/guide/topics/graphics/drawables" rel="noopener noreferrer"&gt;https://developer.android.com/guide/topics/graphics/drawables&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://medium.com/flutter-community/flutter-2019-real-splash-screens-tutorial-16078660c7a1" rel="noopener noreferrer"&gt;https://medium.com/flutter-community/flutter-2019-real-splash-screens-tutorial-16078660c7a1&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://luizmarcus.com/android/construindo-uma-splash-screen-em-flutter/" rel="noopener noreferrer"&gt;https://luizmarcus.com/android/construindo-uma-splash-screen-em-flutter/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://stackoverflow.com/questions/62627690/how-can-i-add-a-basic-splash-screen-with-an-image-and-some-text-to-an-existing-f" rel="noopener noreferrer"&gt;https://stackoverflow.com/questions/62627690/how-can-i-add-a-basic-splash-screen-with-an-image-and-some-text-to-an-existing-f&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://stackoverflow.com/questions/58363128/drawable-v21-vs-v24-vs-custom-folders-for-hdpi-mdpi-xhdpi-etc-in-which-folde" rel="noopener noreferrer"&gt;https://stackoverflow.com/questions/58363128/drawable-v21-vs-v24-vs-custom-folders-for-hdpi-mdpi-xhdpi-etc-in-which-folde&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://stackoverflow.com/questions/3963978/android-xml-files-why-do-predefined-colors-not-work-for-me" rel="noopener noreferrer"&gt;https://stackoverflow.com/questions/3963978/android-xml-files-why-do-predefined-colors-not-work-for-me&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://stackoverflow.com/questions/43879103/adding-a-splash-screen-to-flutter-apps" rel="noopener noreferrer"&gt;https://stackoverflow.com/questions/43879103/adding-a-splash-screen-to-flutter-apps&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://medium.com/flutter-community/splash-screens-for-dark-and-light-mode-in-flutter-eb85f1aa025" rel="noopener noreferrer"&gt;https://medium.com/flutter-community/splash-screens-for-dark-and-light-mode-in-flutter-eb85f1aa025&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://material.io/design/communication/launch-screen.html#placeholder-ui" rel="noopener noreferrer"&gt;https://material.io/design/communication/launch-screen.html#placeholder-ui&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developer.android.com/topic/performance/vitals/launch-time#themed" rel="noopener noreferrer"&gt;https://developer.android.com/topic/performance/vitals/launch-time#themed&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dribbble.com/shots/4291317-Taxi-Splash-Screen" rel="noopener noreferrer"&gt;https://dribbble.com/shots/4291317-Taxi-Splash-Screen&lt;/a&gt;&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>android</category>
      <category>splashscreen</category>
      <category>mobile</category>
    </item>
    <item>
      <title>Como criar um Wizard UI em Flutter?</title>
      <dc:creator>Joabe Ramone</dc:creator>
      <pubDate>Sat, 13 Feb 2021 21:47:23 +0000</pubDate>
      <link>https://forem.com/joaberamone/como-criar-um-wizard-ui-em-flutter-45oo</link>
      <guid>https://forem.com/joaberamone/como-criar-um-wizard-ui-em-flutter-45oo</guid>
      <description>&lt;h2&gt;
  
  
  1 Introdução
&lt;/h2&gt;

&lt;p&gt;Eai clan, tudo certo?&lt;/p&gt;

&lt;p&gt;Hoje eu vim aqui falar sobre um conteúdo bem legal que faz muita diferença quando precisamos coletas muitas informações. &lt;/p&gt;

&lt;p&gt;Sabemos como preencher formulários é bem chato e trabalhoso, e uma das maneiras de tornar mais dinâmico esta tarefa é aplicando uma metodologia de Design.&lt;/p&gt;

&lt;h3&gt;
  
  
  1.1 O que é Wizard ?
&lt;/h3&gt;

&lt;p&gt;Wizard é um padrão de design de interface com o usuário que permite que usuários atinjam um determinado objetivo por meio de uma série de etapas. O usuário insere dados em cada visualização e prossegue para a próxima etapa até a conclusão.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fuuq8fpr3wrt9onc04vjy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fuuq8fpr3wrt9onc04vjy.png" alt="Wizard mago"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Os Wizard's são frequentemente usados ​​para fluxos de integração, em que o usuário precisa inserir um conjunto de informações para começar a utilizar um aplicativo.&lt;/p&gt;

&lt;p&gt;Wizards  são mais usados: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Para uma série de fluxos de entrada de dados confiáveis ​​e ramificados.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Quando os usuários precisam cumprir uma meta que depende de tarefas complexas e conclusão de subtarefas.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  2 Determinar os requisitos e conduzir pesquisas
&lt;/h2&gt;

&lt;p&gt;Por exemplo vamos fazer um aplicativo simples de finanças onde o usuário vai definir suas metas, mas para começar a utilizar o aplicativo ele precisa inserir dados básicos.&lt;/p&gt;

&lt;p&gt;A intenção de usar Wizard é para que os usuários possam ver todas as suas transações categorizadas e contabilizadas para que consigam definir metas financeiras. Com base nessa percepção, determinamos algumas tarefas gerais de inicialização.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fy5b80yj0bsg2zfxm8hox.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fy5b80yj0bsg2zfxm8hox.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Tarefas gerais de inicialização do usuário para o aplicativo de finanças pessoais: adicionar informações pessoais para criar uma conta, conectar bancos, definir metas financeiras.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;A partir daí, determinamos os requisitos de informação com base nessas tarefas gerais.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fn1lv5cw0ighm6qurt668.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fn1lv5cw0ighm6qurt668.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
&lt;code&gt;Requisitos de informação para o aplicativo de finanças pessoais.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;E comece a pensar em agrupamentos lógicos.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fwv7rzkkeu6z3xko89pry.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fwv7rzkkeu6z3xko89pry.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
&lt;code&gt;Agrupamentos de requisitos de informações para o aplicativo de finanças pessoais.&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  3 Crie um fluxo de tarefa
&lt;/h2&gt;

&lt;p&gt;As necessidades de informação são categorizadas e agrupadas em uma sequência de tarefas e subtarefas. O agrupamento de ações relacionadas e as etapas de ordenação reduzem sequencialmente a carga cognitiva, reduzindo a destreza da entrada de dados e fornecendo um caminho claro para a conclusão.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fdardm6yrebrqq1r5tjsr.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fdardm6yrebrqq1r5tjsr.jpg" alt="arvore"&gt;&lt;/a&gt;&lt;br&gt;
&lt;code&gt;Exemplo de um fluxo de tarefa de ramificação.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Frequentemente, o fluxo do usuário se ramifica em caminhos diferentes dependendo das entradas anteriores. Um usuário pode receber uma pergunta que determina uma nova necessidade ou sequência de informações. Essas informações são apresentadas em outra visão ou na visão atual.&lt;/p&gt;

&lt;p&gt;O fluxo de integração de finanças pessoais pode incorporar diferentes fluxos para inserir as informações bancárias de um usuário. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fqcg3c0ljkx7vr4fliiuo.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fqcg3c0ljkx7vr4fliiuo.jpg" alt="Fluxo"&gt;&lt;/a&gt;&lt;br&gt;
&lt;code&gt;Grupos de tarefas de on-boarding de finanças pessoais representados em um stepper.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Então vamos separar em 3 etapas o processo para o usuário criar suas metas financeiras. &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Dados pessoais &lt;/li&gt;
&lt;li&gt;Conectar com o Banco&lt;/li&gt;
&lt;li&gt;Definir metas &lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  4 Criando Wizard em Flutter
&lt;/h2&gt;

&lt;p&gt;Na nossa tela principal vamos criar nossos cards que vai ser nossas três etapas do fluxo de cadastro, então nesta parte vamos colocar as ações onde cada card vai para um formulário diferente.&lt;/p&gt;

&lt;p&gt;Tela do Card:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Variavel&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bool isDadosPessoal = false;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;Card&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;        Row(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  Padding(
                    padding: const EdgeInsets.only(right: 30),
                    child: isDadosPessoal
                        ? Icon(
                            Icons.check_circle,
                            color: Colors.green,
                            size: 45,
                          )
                        : Icon(
                            Icons.circle,
                            size: 45,
                            color: Colors.grey,
                          ),
                  ),
                  FlatButton(
                    minWidth: 250,
                    height: 50,
                    child: Text(
                      'Dados do pessoais',
                      style: TextStyle(fontSize: 18),
                    ),
                    onPressed: () async {
                      bool flag = await Navigator.push(
                          context,
                          MaterialPageRoute(
                            builder: (context) =&amp;gt; PrimeiraPagina(),
                          ));
                      if (flag) {
                        setState(() {
                          isDadosPessoal = flag;
                        });
                      } else {
                        setState(() {
                          isDadosPessoal = false;
                        });
                      }
                    },
                    shape: RoundedRectangleBorder(
                        side: BorderSide(color: Colors.grey[600], width: 2, style: BorderStyle.solid), borderRadius: BorderRadius.circular(0)),
                  ),
                ],
              )
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Flkle2hb7qzrt0fuc73o2.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Flkle2hb7qzrt0fuc73o2.jpg" alt="Card"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Tela do Formulário:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Corpo da tela&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Row(
              children: [
                Text(
                  'Dados Pessoais',
                  textAlign: TextAlign.start,
                  style: TextStyle(fontWeight: FontWeight.w700, fontSize: 20),
                ),
              ],
            ),
            TextField(
              obscureText: true,
              decoration: InputDecoration(
                border: OutlineInputBorder(),
                labelText: 'Nome Completo',
              ),
            ),
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fecxmow2xg9ou5oeorip3.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fecxmow2xg9ou5oeorip3.jpg" alt="Formulario"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Botão de Salvar&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FlatButton(
              minWidth: 200,
              color: Colors.blue,
              height: 42,
              onPressed: () {
                Navigator.pop(context, true);
              },
              child: Text(
                'Salvar',
                style: TextStyle(fontSize: 20, color: Colors.white),
              ),
              shape: RoundedRectangleBorder(
                  side: BorderSide(color: Colors.transparent, width: 2, style: BorderStyle.solid), borderRadius: BorderRadius.circular(20)),
            )
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ffhaim88ytardzdsaq5ob.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ffhaim88ytardzdsaq5ob.jpg" alt="Check"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Agora é só replicar os cards conforme a necessidade, para continuar o nosso exemplo do aplicativo de finanças. Vamos Fazer mais dois card's para completar o fluxo que vai ter este resultado.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ftokg8choeop470jfat7t.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ftokg8choeop470jfat7t.jpg" alt="Wizard completo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusão
&lt;/h2&gt;

&lt;p&gt;Leva horas de pesquisa e atenção para criar um conteúdo como este artigo. Por favor, dê like para me motivar a continuar escrevendo.&lt;/p&gt;

&lt;p&gt;É gratuito para você, mas significa muito para mim. Valeu galera!&lt;/p&gt;

&lt;h2&gt;
  
  
  Referências
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://medium.com/nextux/how-to-design-a-form-wizard-b85fe1cc665a" rel="noopener noreferrer"&gt;How to Design a Form Wizard&lt;/a&gt;&lt;br&gt;
&lt;a href="https://uxdesign.cc/the-wizard-of-user-experience-6926ca41bc9a" rel="noopener noreferrer"&gt;The Wizard of user experience&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/JoabeRamone/wizard-ui" rel="noopener noreferrer"&gt;Exemplo completo no GitHub&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.youtube.com/channel/UCcNWj_53z8qeRxRwsn4OvSQ" rel="noopener noreferrer"&gt;Joabe Ramone YouTube&lt;/a&gt;&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>wizardui</category>
      <category>mobile</category>
      <category>android</category>
    </item>
    <item>
      <title>Como fazer campo de assinatura ou desenho em Flutter.</title>
      <dc:creator>Joabe Ramone</dc:creator>
      <pubDate>Mon, 08 Feb 2021 04:28:46 +0000</pubDate>
      <link>https://forem.com/joaberamone/como-fazer-campo-de-assinatura-ou-desenho-em-flutter-3j1k</link>
      <guid>https://forem.com/joaberamone/como-fazer-campo-de-assinatura-ou-desenho-em-flutter-3j1k</guid>
      <description>&lt;h2&gt;
  
  
  Introdução
&lt;/h2&gt;

&lt;p&gt;Eai, clan. Tudo certo com vocês?&lt;/p&gt;

&lt;p&gt;Hoje quero explicar como que eu fiz pra criar um campo de assinatura manual utilizando Flutter.&lt;/p&gt;

&lt;p&gt;Estamos acostumados a utilizar assinatura digital para assinar documentos, mas existem alguns casos que ainda utilizam este tipo de assinatura. Mas a intenção deste post é para mostrar como você pode estar criando um campo onde pode ser rabiscado. Haha'&lt;/p&gt;

&lt;p&gt;Então vamos partir do principio que temos que fazer uma assinatura em um determinado campo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Separei em dois modos
&lt;/h2&gt;

&lt;p&gt;Eu acho muito importante nós utilizarmos algo que já tenha pronto, para não ficar reinventando a roda. Então eu separei em duas partes de como fazer este campo. &lt;/p&gt;

&lt;p&gt;A primeira maneira é utilizar um plugin Signature que esta disponível no pub.dev. É bem rápido e simples de utilizar.&lt;/p&gt;

&lt;p&gt;Segunda é montar esse campo utilizando CustomPainter do Flutter, é um pouco mais trabalhoso  criar só que você consegue adicionar coisas mais especificas. &lt;/p&gt;

&lt;h2&gt;
  
  
  Utilizando Plugin Signature
&lt;/h2&gt;

&lt;p&gt;Primeiro vai instanciar um controlador com as suas configurações de desenho. Por exemplo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;final SignatureController _controller = SignatureController(
    penStrokeWidth: 4,
    penColor: Colors.black,
    exportBackgroundColor: Colors.transparent,
  );
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Neste controlador coloquei uma espessura de 4, cor preta e um fundo transparente. &lt;/p&gt;

&lt;p&gt;Próximo passa é passar este controlador para o Signature onde vamos assinar ou desenhar.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Signature(
       controller: widget._controller,
       height: 600,
       backgroundColor: Colors.transparent,
      )
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Depois de assinar você pode pegar os bytes em png do controlador e transformar isso em uma imagem.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Image.memory(_controller.toPngBytes())
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Utilizando o Widget CustomPainter
&lt;/h2&gt;

&lt;p&gt;Eu separei cada parte em uma classe que eu criei, você pode conferir o código completo no repositório do Git Hub. Link no final do artigo.&lt;/p&gt;

&lt;h3&gt;
  
  
  Paint e Offset
&lt;/h3&gt;

&lt;p&gt;Paint é uma descrição do estilo a ser usado ao desenhar em um Canvas, e Canvas é uma interface para registrar operações gráficas.&lt;/p&gt;

&lt;p&gt;Então vamos criar uma classe responsável por isso.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class TouchPoints {
  Paint paint;
  Offset points;

  TouchPoints({this.points, this.paint});
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Criar campo para capturar o toque
&lt;/h3&gt;

&lt;p&gt;Criar as variáveis para adicionar os pontos.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  GlobalKey globalKey = GlobalKey();

  List&amp;lt;TouchPoints&amp;gt; points = [];
  StrokeCap strokeType = StrokeCap.round;
  double strokeWidth = 3.0;
  Color selectedColor = Colors.black;
  double opacity = 1.0;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Criar campo para capturar evento do toque.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GestureDetector(
        onPanUpdate: (details) {
          setState(() {
            RenderBox renderBox = context.findRenderObject();
            points.add(_criarTouchPoints(renderBox, details));
          });
        },
        onPanStart: (details) {
          setState(() {
            RenderBox renderBox = context.findRenderObject();
            points.add(_criarTouchPoints(renderBox, details));
          });
        },
        onPanEnd: (details) {
          setState(() {
            points.add(null);
          });
        },
        child: RepaintBoundary(
          key: globalKey,
          child: CustomPaint(
            size: Size.infinite,
            painter: MyPainter(pointsList: points),
          ),
        ),
      ),
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Função responsável por adicionar os pontos.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TouchPoints _criarTouchPoints(renderBox, details) {
    return TouchPoints(
        points: renderBox.globalToLocal(details.globalPosition),
        paint: Paint()
          ..strokeCap = strokeType
          ..isAntiAlias = true
          ..color = selectedColor.withOpacity(opacity)
          ..strokeWidth = strokeWidth);
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Adicionar os pontos no Canvas
&lt;/h3&gt;

&lt;p&gt;Classe usada no CustomPainter para desenhar.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@override
  void paint(Canvas canvas, Size size) {
    for (int i = 0; i &amp;lt; pointsList.length - 1; i++) {
      if (pointsList[i] != null &amp;amp;&amp;amp; pointsList[i + 1] != null) {
        // Desenhar linha quando dois pontos consecutivos estiverem disponíveis
        canvas.drawLine(pointsList[i].points, pointsList[i + 1].points, pointsList[i].paint);
      } else if (pointsList[i] != null &amp;amp;&amp;amp; pointsList[i + 1] == null) {
        offsetPoints.clear();
        offsetPoints.add(pointsList[i].points);
        offsetPoints.add(Offset(pointsList[i].points.dx + 0.1, pointsList[i].points.dy + 0.1));

        //Desenhe pontos quando dois pontos não estiverem próximos um do outro
        canvas.drawPoints(ui.PointMode.points, offsetPoints, pointsList[i].paint);
      }
    }
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Transformar em uma imagem
&lt;/h3&gt;

&lt;p&gt;Precisamos pegar todos os pontos rastreados no nosso Canvas e transformalo em bytes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; RenderRepaintBoundary boundary = globalKey.currentContext.findRenderObject();
    ui.Image image = await boundary.toImage();
    ByteData byteData = await image.toByteData(format: ui.ImageByteFormat.png);
    Uint8List pngBytes = byteData.buffer.asUint8List();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Depois passar esses bytes para este Widget para criar uma imagem.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Image.memory(pngBytes)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusão
&lt;/h2&gt;

&lt;p&gt;Aprender a fundo como as coisas funcionar é muito importante, pode esclarecer vários pontos que passa despercebido. &lt;/p&gt;

&lt;p&gt;Espero ter ajudado, valeu!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/JoabeRamone/Assinatura-Manuel"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Referências:&lt;br&gt;
&lt;a href="https://github.com/vemarav/signature"&gt;Plugin Signature&lt;/a&gt;&lt;br&gt;
&lt;a href="https://api.flutter.dev/flutter/dart-ui/Paint-class.html"&gt;Flutter Paint Class&lt;/a&gt; &lt;br&gt;
&lt;a href="https://api.flutter.dev/flutter/dart-ui/Canvas-class.html"&gt;Flutter Canvas Class&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://api.flutter.dev/flutter/dart-ui/Offset-class.html"&gt;Flutter Offset Class&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=vvI_NUXK00s&amp;amp;t=1s&amp;amp;ab_channel=Flutter"&gt;Video do canal Flutter sobre CustomPaint&lt;/a&gt;&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>android</category>
      <category>dart</category>
      <category>signature</category>
    </item>
    <item>
      <title>Como criar, visualizar e compartilhar PDF em Flutter?!</title>
      <dc:creator>Joabe Ramone</dc:creator>
      <pubDate>Sat, 10 Oct 2020 05:04:30 +0000</pubDate>
      <link>https://forem.com/joaberamone/como-criar-visualizar-e-compartilhar-pdf-em-flutter-43nc</link>
      <guid>https://forem.com/joaberamone/como-criar-visualizar-e-compartilhar-pdf-em-flutter-43nc</guid>
      <description>&lt;h2&gt;
  
  
  Por que resolvi escrever este post
&lt;/h2&gt;

&lt;p&gt;Eai galera DEV, tudo certo?&lt;/p&gt;

&lt;p&gt;Vim aqui publicar mais um post pra poder estar contribuindo para nossa comunidade dev e adquirindo conhecimento. Esse é meu segundo post sobre Flutter, sempre que eu aprender alguma coisa nova eu quero compartilhar com vocês.&lt;/p&gt;

&lt;p&gt;Dessa vez eu tive que implementar um gerador de PDF no meu aplicativo, e como sempre, eu não achei muita coisa em pt-br. Na real eu não achei nada sobre o tema, então resolvi fazer um código de exemplo que subi no GitHub e um post para explicar certinho como fazer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bibliotecas utilizadas
&lt;/h2&gt;

&lt;p&gt;Você vai precisar importar essas bibliotecas no seu &lt;code&gt;pubspec.yaml&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fyv6ixq2tcnkjt2y7co91.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fyv6ixq2tcnkjt2y7co91.png" alt="bibliotecas"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Essas versões sempre são atualizadas, por isso vou deixar os links delas no final do post. Assim você pode instalar a versão mais recente.&lt;/p&gt;

&lt;h2&gt;
  
  
  Criar um PDF
&lt;/h2&gt;

&lt;p&gt;Para criar um PDF em flutter eu utilizei a biblioteca chamada pdf.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fza9z2z4r8o2n1intybpa.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fza9z2z4r8o2n1intybpa.jpg" alt="ava é mesmo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A seguir a função responsável por criar o arquivo em PDF. Nessa função eu passei os atributos separados por parametros, mas seria interessante ser uma lista ou até mesmo um objeto. &lt;br&gt;
O código funciona basicamente assim, eu instanciei um Document e depois adicionei uma pagina nele. E criei uma tabela com meus atributos.&lt;/p&gt;

&lt;p&gt;Depois eu tive que pegar o diretório raiz da aplicação, criei um nome pro meu arquivo temporário e concatenei ele com o diretório raiz. Criado esse caminho, eu preciso salvar o pdf nessa caminho que criei para conseguir acessá-lo a seguir no próximo tópico.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

  _creatPdf(contex, name, lastName, year) async {
    final pdfLib.Document pdf = pdfLib.Document(deflate: zlib.encode);

    pdf.addPage(pdfLib.MultiPage(
        build: (context) =&amp;gt; [
              pdfLib.Table.fromTextArray(data: &amp;lt;List&amp;lt;String&amp;gt;&amp;gt;[
                &amp;lt;String&amp;gt;['Nome', 'Sobrenome', 'Idade'],
                [name, lastName, year]
              ])
            ]));

    final String dir = (await getApplicationDocumentsDirectory()).path;

    final String path = '$dir/pdfExample.pdf';
    final File file = File(path);
    file.writeAsBytesSync(pdf.save());
  }



&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Visualizar um PDF
&lt;/h2&gt;

&lt;p&gt;Para estar visualizando um PDF eu utilizei a biblioteca advance_pdf_viewer.&lt;/p&gt;

&lt;p&gt;Aquele caminho que a gente criou no tópico anterior, vamos estar utilizando para abrir nosso PDF.&lt;/p&gt;

&lt;p&gt;No initState vamos chamar a função responsável por buscar nosso arquivo e atribuir a nossa variavel _doc. &lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

 @override
  void initState() {
    super.initState();
    _initPdf();
  }

  _initPdf() async {
    setState(() {
      _loading = true;
    });
    final doc = await PDFDocument.fromAsset(widget.path);
    setState(() {
      _doc = doc;
      _loading = false;
    });
  }


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Agora temos o arquivo para estar passando pro widget PDFViewer, que ele já vai fazer todo o trabalho de abrir e mostrar o arquivo no corpo do seu Scaffold.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: _loading
            ? Center(
                child: CircularProgressIndicator(),
              )
            : PDFViewer(document: _doc));
  }


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Compartilhar PDF
&lt;/h2&gt;

&lt;p&gt;A biblioteca utilizada foi a share_extend, que basicamente você vai executar a função share, passar o caminho e o tipo do arquivo.&lt;br&gt;
Eu chamei essa função no icone de compartilhamento dentro do meu appBar, é somente você colocá-lo no seu Scaffold.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

AppBar(
          title: Text('Flutter PDF'),
          actions: &amp;lt;Widget&amp;gt;[
            Padding(
              padding: const EdgeInsets.all(8.0),
              child: IconButton(
                  icon: Icon(
                    Icons.share,
                    color: Colors.white,
                  ),
                  iconSize: 30,
                  onPressed: () {
                    ShareExtend.share(widget.path, "file",
                        sharePanelTitle: "Enviar PDF", subject: "example-pdf");
                  }),
            )
          ],
        ),


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Mas espera aí....&lt;/p&gt;

&lt;p&gt;Isso vai dar um erro! E porque?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fyvq4w2irile4kr1v1iys.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fyvq4w2irile4kr1v1iys.gif" alt="pulo do gato"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Por que você tem que dar permissão para abrir esse arquivo.&lt;/p&gt;

&lt;p&gt;No seu arquivo: &lt;code&gt;AndroidManifest.xml&lt;/code&gt; coloque essas permissões:&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

&lt;p&gt;&amp;lt;uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/&amp;gt;&lt;br&gt;
    &amp;lt;uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/&amp;gt;&lt;/p&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Prontinho, tai o resultado!!!&lt;br&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fsi4gwfp8yd0t57vb8zm3.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fsi4gwfp8yd0t57vb8zm3.gif" alt="gerando pdf"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusão
&lt;/h2&gt;

&lt;p&gt;Espero que esse post tenha te ajudado, eu consegui aprender bastante coisa nessa pesquisa que fiz. Vou deixar alguns links que foram de grande ajuda para mim.&lt;/p&gt;

&lt;p&gt;Ah, se quiser dar alguma dica de como fazer melhor pode ficar a vontade a deixar nos comentários. E se você curtiu também!&lt;/p&gt;

&lt;p&gt;Será um grande prazer ter seu feedback! &lt;/p&gt;

&lt;p&gt;Valeu!!!&lt;/p&gt;

&lt;h2&gt;
  
  
  Links úteis
&lt;/h2&gt;

&lt;p&gt;Código completo no GitHub: &lt;a href="https://github.com/JoabeRamone/flutter-pdf" rel="noopener noreferrer"&gt;Joabe Ramone&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=T941X7EKHG8&amp;amp;ab_channel=javico2609" rel="noopener noreferrer"&gt;Video sobre como baixar e compartilhar arquivo&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=sGLqMAnbk1c&amp;amp;ab_channel=javico2609" rel="noopener noreferrer"&gt;Video de como criar um PDF&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  pub.dev
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://pub.dev/packages/pdf" rel="noopener noreferrer"&gt;pdf&lt;/a&gt;&lt;br&gt;
&lt;a href="https://pub.dev/packages/flutter_pdf_viewer/install" rel="noopener noreferrer"&gt;flutter_pdf_viewer&lt;/a&gt;&lt;br&gt;
&lt;a href="https://pub.dev/packages/share_extend/example" rel="noopener noreferrer"&gt;share_extend&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Como usar Snackbar em Flutter?!</title>
      <dc:creator>Joabe Ramone</dc:creator>
      <pubDate>Mon, 28 Sep 2020 19:05:14 +0000</pubDate>
      <link>https://forem.com/joaberamone/como-usar-snackbars-em-flutter-4ce</link>
      <guid>https://forem.com/joaberamone/como-usar-snackbars-em-flutter-4ce</guid>
      <description>&lt;h2&gt;
  
  
  Por que resolvi escrever este post
&lt;/h2&gt;

&lt;p&gt;Eai galera DEV, tudo certo? &lt;/p&gt;

&lt;p&gt;Vim aqui publicar mais um  post pra poder estar contribuindo para nossa comunidade dev e adquirindo conhecimento. &lt;/p&gt;

&lt;p&gt;Nessa semana eu tive que fazer um Snackbar para o meu app de TCC e eu não sabia como poderia ser feito. Na verdade eu não sabia nem o nome do widget, então eu fui pesquisando por “barrinha de alerta mobile” até que encontrei o nome que era utilizado. Depois disso eu fui até a documentação do framework e aprendi como ele funciona, também pesquisei no Design Material suas boas práticas de uso. Vale muito a pena dedicar seu tempo para ler, os links estão no final do post.&lt;/p&gt;

&lt;p&gt;Não achei muita coisa em português e para mim não foi algo tão simples de utilizar, mas depois que eu percorri por vários posts, vídeos e documentação eu consegui entender. Então resolvi juntar tudo em um lugar o que eu aprendi.&lt;/p&gt;

&lt;p&gt;Separei alguns pontos que considero mais fundamentais e importantes na hora de programar. &lt;/p&gt;

&lt;h2&gt;
  
  
  Entenda seu uso
&lt;/h2&gt;

&lt;p&gt;O Snackbar é utilizado para informar ao usuário um processo que foi executado ou irá ser executado. Ele tem que aparecer temporariamente na parte inferior da tela para que não atrapalhe o uso do aplicativo. &lt;/p&gt;

&lt;p&gt;Ele tem basicamente três princípios: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Informativo: Fornece atualização do processo&lt;/li&gt;
&lt;li&gt;Temporário: Ele aparece temporariamente e desaparece por conta própria&lt;/li&gt;
&lt;li&gt;Contextual: É colocado na área mais adequada da interface.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Anatomia
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fm5milnp2ocb1zqqnt4vy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fm5milnp2ocb1zqqnt4vy.png" alt="Anatomia de um snackbar"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Etiqueta de texto&lt;/li&gt;
&lt;li&gt;Recipiente&lt;/li&gt;
&lt;li&gt;Ação (opcional)&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Comportamento
&lt;/h2&gt;

&lt;p&gt;O Snackbar aparece por tempo determinado e depois é fechado sozinho, mas cuidado ao realizar muitas chamadas. Ele tem que aparecer um de cada vez, não deixa fazer uma pilha de Snackbar.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fe9rcnvtqm6i5kyiyt1a0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fe9rcnvtqm6i5kyiyt1a0.png" alt="Exemplo de snackbar empilhado"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Não altere o comportamento dos elementos da tela para mostrar seu Snackbar, isso pode ser uma péssima experiência para o usuário. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fnssceq531vodihfwvzlj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fnssceq531vodihfwvzlj.png" alt="Exemplo snackbar"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Colocação
&lt;/h2&gt;

&lt;p&gt;O Snackbar deve ficar na na parte inferior da interface do aplicativo, mas tem que ter cuidado com o lugar. Ele não pode cobrir a barra de navegação.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fk4harc65aws4gc5xd2hj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fk4harc65aws4gc5xd2hj.png" alt="Exemplo snackbar cobrindo barra de navegação"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Snackbar que abrange toda a largura eu diria que é o mais importante a ter cuidado para o uso, pois até mesmo na documentação do Flutter eles mostram a explicação do snackbar desta maneira.&lt;/p&gt;

&lt;p&gt;Então  isso quer dizer que não podemos usar esse modo que abrange toda a largura da interface? &lt;/p&gt;

&lt;p&gt;Não! &lt;/p&gt;

&lt;p&gt;Pode ser utilizado, mas temos que tomar muito cuidado ao utilizá-lo. Como o exemplo anterior é bem retratado, ele pode cobrir barra de navegação.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Forufp651ogfvtnuspmig.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Forufp651ogfvtnuspmig.png" alt="Exemplo de snackbar com largura total"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Uma boa prática de uso de um snackbar.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F6hseo8f3zlvd418behae.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F6hseo8f3zlvd418behae.png" alt="Exemplo de uma boa pratica do uso de um snackbar"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Mão na massa!
&lt;/h2&gt;

&lt;p&gt;Para utilizar o snackbar é bem simples, basta chamar a função showSnackBar passando o snackbar por parâmetro.&lt;/p&gt;

&lt;p&gt;Desta maneira:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Code Sample for Scaffold.of.',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: Scaffold(
        body: MyScaffoldBody(),
        appBar: AppBar(title: Text('Scaffold.of Example')),
      ),
      color: Colors.white,
    );
  }
}

class MyScaffoldBody extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: RaisedButton(
        child: Text('SHOW A SNACKBAR'),
        onPressed: () {
          Scaffold.of(context).showSnackBar(
            SnackBar(
              content: Text('Have a snack!'),
            ),
          );
        },
      ),
    );
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Mas como na vida nem tudo são rosas, você tem que ficar ligado que o ShowSnackbar é filho do Scaffold. E se você não usar um BuildContext diferente do pai do Scaffold pode dar ruim. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F5a8p2ymwxiczwdy313nz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F5a8p2ymwxiczwdy313nz.png" alt="snackbar é filho do scaffold"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Snackbar Global
&lt;/h2&gt;

&lt;p&gt;A maneira anterior de chamar o snackbar é para uma tela atual somente, isso quer dizer que se você fizer uma mudança de página não irá aparece-lo. Mas tem uma maneira de deixar ele global.&lt;/p&gt;

&lt;h4&gt;
  
  
  Passo 1
&lt;/h4&gt;

&lt;p&gt;Colocar um Scaffold dentro do builder do seu MaterialApp.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class MyApp extends StatelessWidget {
 // This widget is the root of your application.
 @override
 Widget build(BuildContext context) {
   return MaterialApp(
     title: 'Flutter Demo',
     theme: ThemeData(
       primarySwatch: Colors.blue,
       visualDensity: VisualDensity.adaptivePlatformDensity,
     ),
     builder: (context, child) {
       return Scaffold(
         key: GlobalScaffold.instance.scafoldKey,
         body: child,
       );
     },
     initialRoute: '/',
     routes: {
       '/': (_) =&amp;gt; MyHomePage(title: 'Flutter Demo snackbar global'),
       '/second': (_) =&amp;gt; SecondPage(title: 'Segunda página')
     },
   );
 }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Passo 2
&lt;/h4&gt;

&lt;p&gt;Criar uma classe para fazer criar um Scaffold global.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class GlobalScaffold {
 static final GlobalScaffold instance = GlobalScaffold();

 final scafoldKey = GlobalKey&amp;lt;ScaffoldState&amp;gt;();

 void showSnackbar(SnackBar snackBar) {
   scafoldKey.currentState.showSnackBar(snackBar);
 }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Passo 3
&lt;/h4&gt;

&lt;p&gt;Criar a função responsável para invocar o snackbar.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;void onClickSnackbarGlobal() {
 final snackbar = SnackBar(
     behavior: SnackBarBehavior.floating,
     elevation: 150.0,
     content: Text("Eu sou um Snackbar Global!"));
 GlobalScaffold.instance.showSnackbar(snackbar);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Passa 4
&lt;/h4&gt;

&lt;p&gt;Por último é somente chamar a função no seu widget&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@override
Widget build(BuildContext context) {
 return Scaffold(
   appBar: AppBar(
     title: Text(widget.title),
   ),
   body: ListView(
     padding: EdgeInsets.all(20),
     children: [
       RaisedButton(
           child: Text('Ir para segunda página'),
           onPressed: () {
             Navigator.pushNamed(context, "/second");
           }),
       RaisedButton(
         child: Text('Mostrar Sanackbar Global'),
         onPressed: () =&amp;gt; onClickSnackbarGlobal(),
       )
     ],
   ),
 );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Resultado:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F3l1kyhd2buhtoyiztklo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F3l1kyhd2buhtoyiztklo.png" alt="Telas"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusão
&lt;/h2&gt;

&lt;p&gt;Espero que tenha ajudado, qualquer dúvida ou sugestão pode comentar que será de grande ajuda. Valeu!&lt;/p&gt;

&lt;p&gt;Links úteis:&lt;br&gt;
&lt;a href="https://material.io/components/snackbars#specs" rel="noopener noreferrer"&gt;Material Design&lt;/a&gt;&lt;br&gt;
&lt;a href="https://api.flutter.dev/flutter/material/Scaffold/of.html" rel="noopener noreferrer"&gt;Documentação do Flutter&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=zpO6n_oZWw0&amp;amp;ab_channel=Flutter" rel="noopener noreferrer"&gt;Video do canal Flutter explicando o snackbar&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=JdYP9YoO6gU&amp;amp;ab_channel=Flutterando" rel="noopener noreferrer"&gt;Aula do canal Flutterando&lt;/a&gt;&lt;br&gt;
&lt;a href="https://stackoverflow.com/questions/51304568/scaffold-of-called-with-a-context-that-does-not-contain-a-scaffold" rel="noopener noreferrer"&gt;Post no stackoverflow&lt;/a&gt;&lt;/p&gt;

</description>
      <category>android</category>
      <category>flutter</category>
      <category>snackbar</category>
      <category>mobile</category>
    </item>
    <item>
      <title>Code Smells, não deixa para depois.</title>
      <dc:creator>Joabe Ramone</dc:creator>
      <pubDate>Mon, 24 Aug 2020 17:56:36 +0000</pubDate>
      <link>https://forem.com/joaberamone/code-smells-nao-deixa-para-depois-5gnb</link>
      <guid>https://forem.com/joaberamone/code-smells-nao-deixa-para-depois-5gnb</guid>
      <description>&lt;p&gt;Quero abordar um tópico que é na maioria das vezes, esquecido por nós programadores. Passa tão despercebido no nosso dia a dia que futuramente podem causar problema mais profundos. Na maioria das vezes, queremos entregar a tarefa no prazo estimado e nem prestamos atenção que nosso código pode estar com algo estranho, aquele cheirinho de “não tem problema deixar isso ai”. E assim o código vai passando de mão em mão até que a coisa fica grande. E são problemas tão simples que com 2 ou 3 minutos você pode resolver. &lt;/p&gt;

&lt;p&gt;Quero abordar sobre “Code Smells” pois recentemente corrigi vários códigos antigos em um projeto que faço parte da empresa onde trabalho. Eles estavam com cheiro ruim faz tempo, e com isso, aprendi algumas boas práticas a serem usadas. &lt;/p&gt;

&lt;p&gt;Espero que esse post seja um alerta e que possa agregar algo no seu trabalho ou aprendizado.&lt;/p&gt;

&lt;p&gt;Vale reforçar que estou começando a  publicar recentemente e meu propósito é poder ajudar a comunidade DEV e gerar conteúdo em português. Qual quer crítica ou sugestão podem deixar nos comentários que será de grande ajuda, Valeu!&lt;/p&gt;

&lt;p&gt;Bom, vamos ao que interessa. Eu separei dois assuntos para ser bem breve. Primeiro vamos falar de :&lt;/p&gt;

&lt;h2&gt;
  
  
  Variáveis não devem ser sombreadas
&lt;/h2&gt;

&lt;p&gt;Substituir ou obscurecer uma variável declarada em um escopo externo pode impactar fortemente a legibilidade e, portanto, a manutenção de um trecho de código. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Ca8Ej7Ri--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/swvnl21uzxm3blydrvmn.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Ca8Ej7Ri--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/swvnl21uzxm3blydrvmn.jpg" alt="Sombras podem confundir"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Provavelmente você já deve ter visto ou até mesmo feito um código que você recebia uma variavel por parametro, mas tinha o mesmo nome de outra variavel na mesma classe ou espoco.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var y;
var x;
function soma(x, y) {
    return x + y;
}  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Acabei percebendo que isso é comum nos códigos, pelo fato de estar dando o mesmo nome daquela que já foi declarada no escopo,  podendo estar garantindo mais facilidade para identifica-lo. Ou não, isso pode ser um grande problema para outra pessoa ao ler o código.&lt;br&gt;
Essa prática, pode levar as pessoas a introduzirem bugs no código. Porque pensam que estão usando uma variável, mas na verdade estão usando outra. &lt;br&gt;
Pode parecer besta, mas para um código complexo e que não foi você quem o fez. Pode ser que não .&lt;/p&gt;

&lt;p&gt;O segundo assunto é um pouco mais difícil de acontecer com frequência, ou não.&lt;/p&gt;

&lt;h2&gt;
  
  
  Seções de código não devem ser comentadas
&lt;/h2&gt;

&lt;p&gt;"Os programadores não devem comentar o código, pois isso incha os programas e reduz a legibilidade."&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--e0_y3R62--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/tutqve0fgw7a3p7lkc5o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--e0_y3R62--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/tutqve0fgw7a3p7lkc5o.png" alt="comentários em blocos"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Sabemos que os comentários podem ser utilizados para identificar ou explicar algo que está acontecendo no código, por mais que seja uma má prática, muitas vezes usamos. Mas os comentários começam a se tornar um problema quando comentamos seções de código, isso torna o complexo e difícil de entender. Sendo que procuramos fazer o código mais prático possível e aplicando boas práticas para melhorar a leitura das pessoas e não das máquinas.&lt;br&gt;
O código não utilizado deve ser excluído e pode ser recuperado do histórico de controle de origem, se necessário.&lt;/p&gt;

&lt;h2&gt;
  
  
  Considerações finais
&lt;/h2&gt;

&lt;p&gt;Por hora é isso pessoal, quero poder fazer outros post’s abortando sobre “Code Smells” pois acho que é de grande importância. Existe muito mais prática a ser estudada, assim que eu for descobrindo e aprendendo quero estar gerando conteúdo para publicar aqui.&lt;/p&gt;

&lt;p&gt;Para mais informações acesse: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://wiki.sei.cmu.edu/confluence/display/c/DCL01-C.+Do+not+reuse+variable+names+in+subscopes"&gt;https://wiki.sei.cmu.edu/confluence/display/c/DCL01-C.+Do+not+reuse+variable+names+in+subscopes&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://wiki.sei.cmu.edu/confluence/display/java/DCL51-J.+Do+not+shadow+or+obscure+identifiers+in+subscopes"&gt;https://wiki.sei.cmu.edu/confluence/display/java/DCL51-J.+Do+not+shadow+or+obscure+identifiers+in+subscopes&lt;/a&gt;&lt;/p&gt;

</description>
      <category>codequality</category>
      <category>codesmells</category>
      <category>code</category>
    </item>
    <item>
      <title>Como personalizar uma Tag Fixa usando kendo multiselect e AngularJS.</title>
      <dc:creator>Joabe Ramone</dc:creator>
      <pubDate>Tue, 30 Jun 2020 19:28:28 +0000</pubDate>
      <link>https://forem.com/joaberamone/como-personalizar-uma-tag-fixa-usando-kendo-multiselect-e-angularjs-4aol</link>
      <guid>https://forem.com/joaberamone/como-personalizar-uma-tag-fixa-usando-kendo-multiselect-e-angularjs-4aol</guid>
      <description>&lt;p&gt;Resolvi fazer esse post por 3 motivos:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Não achei bastante conteúdo em português.&lt;/li&gt;
&lt;li&gt;Quero ajudar a comunidade DEV.&lt;/li&gt;
&lt;li&gt;Aprender a fazer publicação.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Eu tinha uma tarefa para ser feita na empresa que eu trabalho, onde precisava fazer um Multi Select com uma Tag fixa. Contendo o nome do primeiro item selecionado e mais a quantidade de itens selecionados.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Gv48h3qW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/n8pa78g7ikqfej6qnvoc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Gv48h3qW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/n8pa78g7ikqfej6qnvoc.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Só que o problema era que a versão do Kendo era antiga e não tinha muitos recursos, então procurei algumas soluções para fazer esse Multi Select.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  &amp;lt;select id="idCombo"
          kendo-multi-select
          k-ng-model="valoresSelecionados"
          k-options="kendoOptions"&amp;gt;
  &amp;lt;/select&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Para controlar o nome fixo no input, eu precisei colocar como atributo no Options do Kendo, ou seja, primeiramente o campo &lt;code&gt;tagMode&lt;/code&gt; deve ser 'single'. Depois eu precisei fazer um template pra ficar do jeito que queria, aparecendo o nome no campo. Exemplo do atributo options passado pro kendo, pode variar de acordo da estrutura do projeto.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;options = {
            dataTextField: 'nome', //campo que vai aparecer na combo
            autoClose: true, //fechar toda vez que selecionar 
            tagMode: 'single', //Deixa uma tag fixa
            tagTemplate: '&amp;lt;span&amp;gt; {{ nome }} + {{ valoresSelecionados.length }} &amp;lt;/span&amp;gt;', 
        };
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Para fazer com que o nome do campo ficasse dinâmico, eu criei um observador &lt;code&gt;$watch&lt;/code&gt; do AngularJS. Então toda vez que o meu array &lt;code&gt;$scope.valoresSelecionados&lt;/code&gt; tivesse alguma modificação é executado um função anônima que coloca o primeiro nome no &lt;code&gt;$scope&lt;/code&gt;. Saiba mais sobre isso nesse link. &lt;a href="https://docs.angularjs.org/api/ng/type/%24rootScope.Scope#%24watch"&gt;https://docs.angularjs.org/api/ng/type/$rootScope.Scope#$watch&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$scope.$watch('valoresSelecionados', function () {
                if ($scope.valoresSelecionados.length &amp;gt; 0) {
                    $scope.nome = $scope.valoresSelecionados[0].nome);
            });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Espero ter ajudado em algo, esse foi meu primeiro post aqui no DEV e pretendo postar mais sugestões.&lt;/p&gt;

&lt;p&gt;Qual quer duvida ou sugestão pode comentar que vou ficar feliz! &lt;/p&gt;

&lt;p&gt;Vlw!&lt;/p&gt;

</description>
      <category>angular</category>
      <category>kendo</category>
      <category>multiselect</category>
      <category>frontend</category>
    </item>
  </channel>
</rss>
