Olá! Boas-vindas ao curso de Flutter com Web API: Integrando sua aplicação. Meu nome é Ricarth Lima e eu serei seu instrutor nessa jornada.
Por uma questão de acessibilidade, vou me autodescrever: sou um homem de pele clara e tenho cabelos bem cacheados, quase crespos, olhos castanhos, um nariz grande e uma boca larga. Eu uso óculos de armação retangular escura e tenho uma barba medianamente espessa. Durante a maioria do curso, usarei uma camisa azul escura.
Agora vamos falar de algo importante que vocês precisam saber antes de começarem este curso, ou seja, dos pré-requisitos. É essencial que tenham uma boa base de Dart para fazerem esse curso, então recomendo fortemente que concluam a Formação de Dart.
Outro requisito muito importante é o curso Flutter: persistência interna. Também é importante terem assistido o Alura+ Flutter: como usar navegação nomeada, porque esse conhecimento será muito usado neste curso.
Ao final deste curso, produziremos um simples aplicativo de diário, inclusive o nome é justamente Diário Simples. Nele, a pessoa poderá registrar os progressos de cada dia, como foi o dia e assim por diante. Vamos conferir o protótipo.
Notamos que temos uma tela inicial com uma App Bar de cor preta e alguns itens em uma lista. Esses itens variam se o dia foi preenchido com alguma informação ou não. Quando o dia é preenchido com uma informação, temos em destaque o dia da semana e do mês, além de um trecho do começo da anotação da pessoa.
Se o dia não foi preenchido, temos apenas o espaço com o dia da semana e do mês. Clicando no dia que não foi preenchido, vamos para uma tela onde podemos escrever um texto e salvá-lo, registrando esse dia na lista.
Outro recado extremamente importante é sobre as versões. Sabemos que o Flutter se atualiza com muita frequência. Às vezes essas atualizações acabam quebrando o código, o que pode prejudicar seu o entendimento e avanço do curso.
Então recomendo fortemente que utilizem a versão 3.0.5 do Flutter, com a versão 2.17.6 do Dart. Conforme instalarmos as dependências durante o curso, também reforçaremos sobre a questão das versões, para evitar o máximo de frustração possível.
Além disso, aprenderemos algumas funcionalidades técnicas durante o curso. Aprenderemos sobre temas e fontes, e como usar isso a nosso favor para construirmos uma aplicação o mais parecida possível com o protótipo. É um tema bem interessante e é sempre bom revisarmos e aprendê-lo durante os cursos de Flutter.
Também aprenderemos a criar IDs únicos, usando o UUID, e entenderemos um pouco sobre como a Internet funciona, para servir de base para os nossos entendimentos de comunicação com a Web API. Descobriremos como configurar uma API local, como instalar a biblioteca HTTP e como usá-la para fazer requisições para nossa API.
Além disso, aprenderemos a usar interceptadores e loggers para tornar a visualização das nossas requisições mais agradável. Também aprenderemos a converter um objeto para texto, para que ele possa ser mandado pelo canal da Internet e possa ser interpretado ao chegar no servidor.
E claro, como é Flutter, aprenderemos a fazer isso tudo criando e configurando telas e widgets, para tornar as aplicações o mais bonitas e eficientes possível. Também entenderemos como criar e configurar telas no Flutter para fazer todo esse trabalho de comunicação.
Estou muito animado para começar essa aventura e espero que vocês também estejam.
Vejo vocês no próximo vídeo.
Até lá!
Agora que já nos conhecemos, é importante dizer que, na vida real, nem sempre começaremos nossos projetos do zero. Na verdade, é bem comum que tenhamos que dar continuidade a um projeto já iniciado, ou seja, pegar um projeto que alguém já começou e adicionar novas funcionalidades a ele.
Para exercitarmos essa característica, neste curso aprenderemos a partir de um projeto já iniciado. Trata-se de um simples aplicativo de diário, que possui algumas funcionalidades básicas prontas, mas o principal, que é usar a Web API para guardar os dados, ainda não está implementado. Então é o que faremos.
O projeto está disponível nesta atividade. Então vamos conferir detalhadamente o código que já temos para, aos poucos, entendermos o que está pronto.
Primeiramente, vamos analisar o emulador. Notamos que, até o momento, temos apenas uma tela. Essa tela tem uma App Bar de cor azul, com uma data no canto esquerdo, e uma lista de elementos abaixo da App Bar.
Percebemos que há dois tipos de elementos nesta lista. Um dos elementos tem o dia da semana e o dia do mês, no formato "SSS - D", onde "SSS" representa as três primeiras letras do dia da semana e o "D" é o dia do mês.
O outro elemento já tem algumas informações a respeito de um registro. Ele contém o dia do mês mais destacado, no lado esquerdo, e uma parte do texto da entrada, exibido no lado direito. É isso que já temos pronto, agora vamos conferir como isso se comporta no código.
Primeiramente, vamos conferir nossa estrutura de pastas. Ao acessarmos a pasta "lib" no Explorador, notamos que ela contém quatro pastas e a main.dart
. Já sabemos que a main.dart
é por onde começamos a rodar nosso programa, mas antes vamos conferir as demais pastas.
Começaremos por "lib > models", porque olhar os models de uma aplicação diz muito sobre ela. Na pasta "models" teremos apenas um modelo, que é o journal.dart
. "Journal" se traduz do inglês como "Diário", ou seja, journal é a entrada de um diário.
Ao abrirmos o journal.dart
, observamos que o código tem quatro propriedades: String id
, String content
, DateTime createdAt
e o updatedAt
, que também é um DateTime
.
class Journal {
String id;
String content;
DateTime createdAt;
DateTime updatedAt;
//Código suprimido
}
Então temos um ID (id
) e o próprio conteúdo (content
), ambos em forma textual, além do "Criado em" (createdAt
), que registra quando a entrada no diário foi criada, e o "Atualizado em" (updatedAt
), que registra a data da última atualização dessa entrada. Fora isso, se descermos para a linha 15, observamos que já existe um toString()
implementado. Assim ele mostrará essas informações quando tentarmos imprimir um objeto instanciado dessa classe.
//Código suprimido
@override
String toString() {
return "$content \ncreated_at: $createdAt\nupdated_at:$updatedAt";
}
Esse é o nosso "model", agora vamos para a próxima pasta, que é a "lib > database". Precisamos prestar muita atenção ao database.dart
. Esse database é virtual e existe para preencher a tela agora, já que ainda não temos os dados vindos de uma Web API. Isso significa que são dados autogerados.
Abrindo novamente o emulador, observamos que temos a mensagem "Entrei na comunidade da Alura no Discord" no dia 6, que é um sábado. Se atualizarmos a aplicativo Flutter, clicando no Hot Restart, e navegarmos pelo App, encontramos três mensagens: uma no dia 31, que é um domingo, uma no dia 2, que é uma terça, e a mesma mensagem do dia 6.
O database.dart
tem um pequeno escopo de mensagens que ele gera automaticamente para conseguirmos testar a tela enquanto não temos a funcionalidade da Web API, que implementaremos a seguir. Portanto é isso que o database faz.
Vocês não precisam se preocupar tanto com a forma que esse código funciona, porque o database.dart
só está servido de exemplo, mas eu queria esclarecer a linha 22 deste código: a String id = const Uuid().v1()
. Ela informa que nossos IDs utilizarão o padrão UUID, que é basicamente um identificador universal único.
É bem comum que as linguagens de programação tenham uma biblioteca que gere um ID único com o padrão UUID, que é um número enorme de 128 bits, representado de forma hexadecimal. Assim, é gerado um ID com uma chance baixíssima de ser repetido, matematicamente falando. Por isso ele é bem legal e é o que usaremos. Aprenderemos mais sobre o UUID posteriormente.
Além disso, o database.dart
usa a biblioteca Random()
para gerar aquelas informações. Então há um intervalo de dias com algumas possibilidades de entradas no diário, usando mensagens aleatórias. Simples assim.
Na sequência, acessaremos "lib > helpers". Vou apresentar a vocês nossos "helpers", ou seja, nossos "ajudadores". É bem comum termos pastas com funções ou classes que nos ajudam de algum modo e, neste caso, temos duas delas: phrases (frases) e weekday (dia da semana).
No phrases.dart
temos as frases que aparecem no aplicativo de forma aleatorizada, então esse arquivo é bem tranquilo de entender. Já no arquivo weekday.dart
, observamos que temos um int weekday
na linha 3, dentro da classe WeekDay
.
O weekday
varia de 1 a 7, representando de segunda a domingo, então transformamos esse número em uma entrada textual que mostramos na tela. Para cada um dos números, criamos, a partir da linha 7, uma entrada curta (short
), por exemplo "dom"
, e uma entrada longa (long
), por exemplo, "Domingo"
. Portanto, com uma instância da classe WeekDay
, conseguimos ter uma formatação do dia para usarmos no nosso código.
Por fim, chegaremos nas nossas telas, acessando "lib > screens > home_screen". Por enquanto, temos apenas a home screen, no arquivo home_screen.dart
, mas para cada tela que fizermos, criaremos uma pasta dentro de "screens" com o nome da tela, por exemplo "home_screen".
Caso queiramos modularizar alguns widgets, também criaremos a pasta "widgets" dentro da pasta com o nome da tela, como aconteceu com a Home Screen. Portanto, dentro da pasta "home_screen", temos a pasta "widgets" e o arquivo home_screen.dart
.
Primeiramente, vamos abrir a home_screen.dart
, inclusive podemos fechar o Explorador para vermos melhor o código. A Home Screen é um Stateful Widget onde teremos um dia, que é a data de hoje. Futuramente podemos até fazer uma página para voltarmos aos históricos antigos, mas basicamente temos o dia atual.
A partir desse dia, definiremos o tamanho da janela a ser visualizado. Voltando para o emulador e rolando até o final da tela, notamos que começa com o dia 8. Ao rolarmos para o começo da lista, na parte de cima da tela, notamos que acaba no dia 29.
Isso significa que temos uma janela de 20 dias para visualizarmos nossas entradas, sendo 10 dias na parte de cima da tela e 10 dias na parte de baixo. Além disso, precisamos prestar muita atenção na linha 22 do home_screen.dart
.
Map<String, Journal> database = {}
Nessa linha estamos inicializando nossa variável database
, que é o um Map<>
de String
para Journal
, onde a String
é o ID e o Journal
é uma entrada no nosso diário. Com isso, a tela consegue mostrar as entradas registradas, ou seja, se existir uma entrada no sábado do dia 6, ela estará no database
e aparecerá na tela do nosso app.
Caso não exista um registro, ele mostra um espaço vazio apenas com a data. Assim, no futuro, implementaremos o Click
para pessoa adicionar um registro para essa data.
Além disso, no home_screen.dart
temos a criação dessa tele que vemos no aplicativo. Portanto, na linha 41, dentro do body
, temos uma ListView()
com um controller
, onde vamos controlar o comportamento de scroll (rolagem) dessa lista. Com isso, posteriormente conseguiremos acessar o ponto da lista que quisermos.
Como filho (children
) da ListVIew()
, na linha 43 temos o método generateListJournalCards()
, que apresentarei na sequência. Esse método gera uma lista com esses cards que temos na tela, e chegaremos a ele em breve. Por fim, na linha 52 da home_screen
, temos uma função de refresh()
para essa lista.
void refresh() {
setState(() {
database = generateRandomDatabase(maxGap: windowPage, amount: 3);
});
}
Agora vamos conferir o método generateListJournalCards
, acessando "lib > screens > home_screen > widgets > home_screen_list.dart". Não precisaremos alterar esse método, porque a lógica dele já está pronta. Só alteraremos no database
quando estivermos usando a Web API. Contudo vou explicar como ele funciona.
O generateListJournalCards
gera uma lista de cards vazios, como observamos na linha 9. Esses cards vazios são aqueles que, no aplicativo, têm apenas o dia da semana e do mês, como "sex - 5". Depois ele confere o database
, que passamos via parâmetro, como na linha 17, e onde tiver uma data com um journal ou algo escrito, ele transforma em cartão.
Portanto no dia em que a pessoa adicionou uma entrada no diário, ele mostra o card de conteúdo no aplicativo, que é o card com o dia do mês e da semana em destaque e parte do registro. Se o dia não tiver conteúdo, ele manterá o card vazio, conforme o código da linha 12. O retorno do generateListJournalCards
é uma lista na forma de um widget chamado Journal Card.
Se redirecionarmos o código para JournalCard
, vamos para o segundo arquivo da pasta "widgets", que é o journal_card.dart
. Notaremos que ele é um StatelessWidget
que mostra, finalmente, a lista na tela.
Então vamos recapitular em tudo que conhecemos até agora. Temos uma estrutura de pastas compostas de, basicamente: database, helpers, models, screens e do arquivo main.dart
, onde rodaremos o código.
Na "models" é onde temos nosso modelo do journal, que representa a entrada que queremos fazer no nosso diário. O arquivo da "database" serve para, enquanto não tivermos um banco de dados de verdade, conseguirmos acessar aleatoriamente alguns exemplos de registro para construirmos nossas telas.
Na pasta "helpers" temos arquivos que nos ajudam a mostrar as coisas de forma mais veloz e ágil, de acordo com o que queremos. Já na pasta "screens", onde temos nossas telas, temos o arquivo da ListView
que gera alguns desses cards, dependendo do que tem no database
.
Por último, vale ressaltar que estamos usando rotas nomeadas, então, como falei no vídeo anterior, é bem importante que vejam o Alura+ de Flutter sobre rotas nomeadas. Apesar disso, não muito complicado, como podemos observar na linha 18 da main.dart
.
Basicamente definimos, através de um Map
, quais são nossas rotas, com o routes: {}
. Além disso, como mostra a linha 17, definimos qual é a rota inicial através da inicialRoute
.
Espero que tenham compreendido e vejo vocês logo mais, quando transformaremos esse projeto que já está rodando em algo cada vez mais parecido com o que vimos no protótipo.
Antes de irmos para a Web API, é importante saber que, ao trabalharmos um projeto já iniciado, é bem normal precisarmos fazer algumas alterações para ele se tornar apto para receber nossas novas funcionalidades. Pensando nisso que, neste vídeo, vamos mudar a aparência do nosso projeto para ele ficar mais parecido com o que foi pedido no protótipo.
Vamos para o código da main.dart
, porque é nele onde começaremos. Como sabemos, o Material App tem algumas propriedades muito impactantes na nossa aplicação, sendo algumas delas relacionadas ao tema. Por exemplo, temos o theme
, que significa "tema", então vamos codá-lo na linha 15.
Ao passarmos mouse sobre ele, descobrimos que ele espera um ThemeData
. Já existem alguns temas pré-definidos, mas também podemos criar o nosso. Sendo assim a linha 15 fica theme: ThemeData(),
.
//Código suprimido
return MaterialApp(
title: 'Simple Journal',
debugShowCheckedModeBanner: false,
theme: ThemeData(),
darkTheme: ThemeData.dark(),
themeMode: ThemeMode.light,
initialRoute: "home",
routes: {
"home": (context) => const HomeScreen(),
},
);
Algo que podemos notar é que já existiam alguns códigos nesse arquivo. Acabamos de criar o nosso tema, mas já existia o darkTheme
, que é o tema escuro, na linha 16, e o themeMode
, que é o modo do tema, na linha 17.
No themeMode
, escolheremos entre o modo de tema claro, que é o que vamos configurar neste vídeo, e o escuro, que poderíamos fazer com outra configuração de cores e comportamentos baseado em um tema escuro. Assim a pessoa conseguiria definir tanto via aplicativo ou via sistema se ela quer ver o tema claro ou escuro.
Para exemplificar, se observamos a linha 17, percebemos que o tema ligado por padrão é o claro: ThemeMode.light
. Além disso, no dispositivo, reparamos que o fundo da tela é branco e os componentes da tela tem cores claras, como esperamos em um tema claro.
Como também vimos, na linha 16 ele tem uma predefinição do ThemeData
para o modo escuro, ou seja, ThemeData.dark()
. Se mudarmos o final da linha 17 para ThemeMode.dark
, ao invés de exibir o app com o tema da linha 15, ele usa o tema da linha 16. Vamos salvar e, após o Hot Reload, notamos que o aplicativo mudou para o modo escuro.
Entretanto, o tema escuro é mais difícil de mudarmos até chegarmos ao tema do protótipo do que o tema claro. Sendo assim, na linha 17, voltaremos o código para ThemeMode.light
e faremos as alterações a partir do tema claro mesmo.
A primeira coisa que mudaremos é uma propriedade chamada primarySwatch
, então vamos codá-la dentro do ThemeData()
da linha 15. Swatch significa, basicamente, amostra ou paleta, então primary swatch pode ser traduzido como paleta primária.
Se deixarmos o mouse sobre o primarySwatch
, a documentação nos informa que ela espera uma MaterialColor
. Nesse momento, isso significa que não é toda cor pré-definida ou criada via ARGB, que conseguiremos passar, porque essas são colors (Color
), enquanto é esperado uma MaterialColor
.
A diferença entre uma Color e uma Material Color, além do nome, é que a MaterialColor
possui várias cores ou gradações de uma mesma cor, e é ela que esperamos no primarySwatch
. Observaremos isso no exemplo.
Então, na linha 16, codaremos Color.
. Isso abre um menu de opções que, inclusive, nos possibilitaria criar nossa própria cor, contudo usaremos o .grey
. Portanto a linha 16 fica primarySwatch: Colors.grey
.
//Código suprimido
theme: ThemeData(
primarySwatch: Colors.grey,
),
Ele aceitou o .grey
e, ao voltarmos para o aplicativo, conseguimos observar o que mudou. A mudança mais significativa está na cor da App Bar, que agora está cinza.
Vamos analisar o que acontece se quiséssemos criar uma cor, como o vermelho com .fromARGB(a, r, g, b)
. Na linha 15 vamos substituir o .grey
por .fromARGB(255, 255, 0, 0)
, ou seja, o alpha e o vermelho são 255 e o verde o azul são 0. Usamos um vermelho em intenso, mas não funciona e logo temos uma marcação de erro.
Isso acontece porque o primarySwatch
espera uma MaterialColor
, mas demos uma Color
. Para finalizar esse assunto de Color
e MaterialColor
, se voltarmos a linha 17 para Colors.grey
e usaremos o "Ctrl + Botão direito do mouse" sobre o .grey
para acessarmos a documentação.
O comando abre o arquivo colors.dart
e nele reparamos que a MaterialColor grey
tem vários códigos de cor dentro dela, além da cor principal, que é o cinza que estamos vendo. Neste caso, a cor principal está na linha 1834: 500: Color(_greyPrimaryValue)
.
O primarySwatch
espera um Material Color porque ele não usa apenas a cor principal. Para cada detalhe, como a sombra do botão, tipos diferentes de botões e até a App Bar, ele usa uma gradação diferente baseada em um padrão. Por isso ele espera uma amostra de cores, que é o caso de uma MaterialColor
, portanto usaremos o Colors.grey
no primarySwatch
.
Mesmo assim percebemos que nossa App Bar está diferente daquela no nosso protótipo. Existe uma forma de mudarmos isso diretamente na ThemeData()
, usando a propriedade appBarTheme
. Com ela conseguimos mudar todas as App Bars da nossa aplicação a partir do ThemeData()
.
Isso é muito importante. Imaginem que temos esse padrão e precisamos aplicá-lo nas App Bars de uma em uma. Isso demora bastante e não é eficiente. Além disso, se tivermos que mudar algo, teria que mudar em todas, o que não é legal.
Portanto a melhor forma de fazer isso é mudando com o appBarTheme
, de forma que todas recebam o mesmo padrão. E se quisermos uma especificidade em alguma App Bar, mudamos diretamente nela.
Antes de começarmos esse processo, vamos analisar bem a nossa App Bar atual. Na tela do aplicativo, observamos que a App Bar está cinza, mas segundo o protótipo, ela será preta. Ela também está com uma sombra, que não queremos, e não podemos manter o texto preto, porque ele sumirá na barra preta. Então queremos o texto branco. São essas as alterações que queremos fazer, por enquanto, na nossa App Bar.
Voltando para o código, deixaremos o mouse sobre o appBarTheme
para descobrirmos o que ele recebe, que é justamente um AppBarTheme()
. Então, na linha 17, codamos appBarTheme: AppBarTheme()
.
Começaremos corrigindo a cor de fundo. Sendo assim, nos parênteses (()
), codaremos color
e, dentre as opções de menu, selecionamos a backgroundColor
. Nesse caso não precisamos de uma MaterialColor
, apenas de uma Color
, então podemos passar qualquer cor, no caso, Colors.black
.
//Código suprimido
theme: ThemeData(
primarySwatch: Colors.grey,
appBarTheme: AppBarTheme(backgroundColor: Colors.black),
),
Vamos salvar e executar o aplicativo. Ao abrirmos novamente o dispositivo, reparamos que a App Bar está completamente preta. Não é exatamente o que queríamos, mas estamos chegando em algum lugar.
Sendo assim, o segundo ponto é mudarmos o estilo do texto, para que ele fique branco. Portanto, depois da backgroundColor
, usaremos o titleTextStyle: TextStyle()
, que usamos bastante. Dentro dos parênteses passaremos o color: Colors.white
.
Por fim, vamos formatar o código e salvar. No caso, ele está com uma marcação informando que esse código precisa ser const
, já que não há nenhuma variável envolvida, mas cuidaremos disso no final.
//Código suprimido
theme: ThemeData(
primarySwatch: Colors.grey,
appBarTheme: AppBarTheme(
backgroundColor: Colors.black,
titleTextStyle: TextStyle(color: Colors.white),
),
),
Quando voltamos para o aplicativo, percebemos que o texto da App Bar está na cor branca e permaneceu no lado esquerdo, mas ficou com uma fonte menor, como no protótipo. Então falta apenas removermos a sombra abaixo da App bar, e fazemos isso usando outra propriedade da appBarTheme
, chamada elevation.
Portanto, na linha 18, como primeira propriedade, codamos elevation: 0,
. Depois vamos formatar e salvar o código para rodar o aplicativo.
Quando o app abre, observamos que a sombra sumiu. Sendo assim, agora podemos voltar para o código e adicionar o const
na linha 17, antes de AppBarTheme()
, para não termos o linter, que é a marcação que nos lembra do const
.
//Código suprimido
theme: ThemeData(
primarySwatch: Colors.grey,
appBarTheme: const AppBarTheme(
elevation: 0,
backgroundColor: Colors.black,
titleTextStyle: TextStyle(
color: Colors.white
)
),
),
//...
O último detalhe que falta é adicionarmos a fonte que esperamos. Existem várias formas de adicionarmos as fontes, mas usaremos o método que é através do Google Fonts. Assim conseguiremos ter acesso a qualquer fonte do Google Fonts, o que é bem legal. Então vamos para o navegador para aprendermos como fazer.
Quem desenvolve em Front-End conhece muito bem o Google Fonts. Caso vocês ainda não conheçam, esse aqui é o repositório de fontes gratuitas da Google, onde conseguimos acessar diversas fontes.
Para acessarmos essas fontes no nosso repositório Dart, existe uma dependência. Então vamos acessar o pub.dev e na barra de busca digitamos "google fonts".
Vamos observar os resultados da busca com atenção para escolhermos a opção correta. A "google_font", que usaremos, é certificada pelo "material.io", possui a tag "Flutter Favorite" e, no canto superior direito do resultado, notamos que ela tem popularidade de 100%.
Clicaremos na extensão "google_fonts" para acessá-la e depois clicamos em "Installing", que é o quarto botão da barra de opções abaixo do nome e das demais informações sobre a extensão. Descendo um pouco a página, acessaremos o código que usaremos, com a versão 3.0.1.
dependencies:
google_fonts: ^3.0.1
Mais uma vez conversaremos sobre versões, porque é possível que o "google_fonts" esteja em uma versão muito superior a essa no momento em que estiverem assistindo a este curso. Ainda assim, recomendo que usem a versão 3.0.1, que está sendo usada nesse curso, para não termos discrepâncias no aprendizado.
Sendo assim, copiaremos o google_fonts: ^3.0.1
e voltaremos para o nosso código. Em seguida, vamos abrir o explorador do projeto e acessar o arquivo pubspec.yaml
. Feito isso, na linha 17, logo abaixo do uuid
, adicionaremos o código que copiamos e vamos salvar.
//Código suprimido
dependencies:
flutter:
sdk: flutter
cupertino_icons: ^1.0.2
uuid: ^3.0.6
google_fonts: ^3.0.1
Quando salvamos, ele roda para nós o Flutter pub get. Além disso, como já sabemos, por termos criado uma nova dependência, precisamos parar a execução do nosso código e rodar novamente.
Enquanto o app roda, podemos voltar para o main.dart
e configurar nosso ThemeData()
para receber o google_fonts
, o que é bastante simples. Na linha 24, após o fechamento da AppBarTheme()
, codamos a propriedade textTheme:
e digitamos Go
. Com isso, surge um menu de opções onde escolheremos a GoogleFonts
que importa automaticamente o pacote de fontes da Google.
theme: ThemeData(
primarySwatch: Colors.grey,
appBarTheme: const AppBarTheme(
elevation: 0,
backgroundColor: Colors.black,
titleTextStyle: TextStyle(
color: Colors.white
),
),
textTheme: GoogleFonts
),
Em seguida, codaremos um ponto final (.
) e, assim, aparece o menu com todas as fontes que disponíveis nessa dependência. A que usaremos, ou seja, a do nosso protótipo, é a bitter. Usaremos na forma de textTheme
, que é para onde iremos passar, então codamos GoogleFonts.bitterTextTheme()
. Caso quiséssemos usar diretamente em um texto, poderíamos usar apenas GoogleFonts.bitter()
.
//Código suprimido
theme: ThemeData(
primarySwatch: Colors.grey,
appBarTheme: const AppBarTheme(
elevation: 0,
backgroundColor: Colors.black,
titleTextStyle: TextStyle(
color: Colors.white
)
),
textTheme: GoogleFonts.bitterTextTheme()
),
//...
Ao salvarmos e voltarmos para o aplicativo, percebemos que nossa fonte já mudou para uma fonte com serifa, que lembra mais uma anotação e diário. Com isso, também deixamos mais parecido com o protótipo. Agora vamos recapitular rapidamente o que fizemos.
Aprendemos que o ThemeData()
é o que define como o tema da nossa aplicação irá se comportar. Também descobrimos que podemos variar do modo escuro para o modo claro, e que estamos usando o modo claro, no qual fizemos algumas alterações.
Primeiramente mudamos todas as App Bars para que elas sigam o padrão de cor preta, texto branco e sem sombra. Depois mudamos o tema da fonte para ela ser uma fonte que vem do Google. Para isso, instalamos uma dependência e usamos a fonte .bitter
no textTheme
.
Agora que está tudo como o esperado, conversaremos sobre conceitos fundamentais para entendermos quando e porque usar Web APIs.
O curso Flutter com WebAPI: integrando sua aplicação possui 203 minutos de vídeos, em um total de 48 atividades. Gostou? Conheça nossos outros cursos de Flutter em Mobile, ou leia nossos artigos de Mobile.
Matricule-se e comece a estudar com a gente hoje! Conheça outros tópicos abordados durante o curso:
Impulsione a sua carreira com os melhores cursos e faça parte da maior comunidade tech.
1 ano de Alura
Assine o PLUS e garanta:
Formações com mais de 1500 cursos atualizados e novos lançamentos semanais, em Programação, Inteligência Artificial, Front-end, UX & Design, Data Science, Mobile, DevOps e Inovação & Gestão.
A cada curso ou formação concluído, um novo certificado para turbinar seu currículo e LinkedIn.
No Discord, você tem acesso a eventos exclusivos, grupos de estudos e mentorias com especialistas de diferentes áreas.
Faça parte da maior comunidade Dev do país e crie conexões com mais de 120 mil pessoas no Discord.
Acesso ilimitado ao catálogo de Imersões da Alura para praticar conhecimentos em diferentes áreas.
Explore um universo de possibilidades na palma da sua mão. Baixe as aulas para assistir offline, onde e quando quiser.
Acelere o seu aprendizado com a IA da Alura e prepare-se para o mercado internacional.
1 ano de Alura
Todos os benefícios do PLUS e mais vantagens exclusivas:
Luri é nossa inteligência artificial que tira dúvidas, dá exemplos práticos, corrige exercícios e ajuda a mergulhar ainda mais durante as aulas. Você pode conversar com a Luri até 100 mensagens por semana.
Aprenda um novo idioma e expanda seus horizontes profissionais. Cursos de Inglês, Espanhol e Inglês para Devs, 100% focado em tecnologia.
Transforme a sua jornada com benefícios exclusivos e evolua ainda mais na sua carreira.
1 ano de Alura
Todos os benefícios do PRO e mais vantagens exclusivas:
Mensagens ilimitadas para estudar com a Luri, a IA da Alura, disponível 24hs para tirar suas dúvidas, dar exemplos práticos, corrigir exercícios e impulsionar seus estudos.
Envie imagens para a Luri e ela te ajuda a solucionar problemas, identificar erros, esclarecer gráficos, analisar design e muito mais.
Escolha os ebooks da Casa do Código, a editora da Alura, que apoiarão a sua jornada de aprendizado para sempre.