Alura > Cursos de Mobile > Cursos de Flutter > Conteúdos de Flutter > Primeiras aulas do curso Persistência com Flutter: crie um app com armazenamento interno

Persistência com Flutter: crie um app com armazenamento interno

Implementando o Dashboard - Introdução

Boas vindas!

Sou o instrutor Alex Felipe, e este é o curso de Persistência de Dados Internos em Flutter.

Para que possamos evoluir nossas habilidades, absorver o conteúdo integral e ter o melhor aproveitamento possível, é importante já ter todos os conhecimentos apresentados nas aulas de Fundamentos de Flutter aqui da Plataforma Alura. Com este pré-requisito, entenderemos bem o que será visto ao longo deste curso.

Sobre o projeto, faremos a implementação oficial do aplicativo da Bytebank, começando pela tela inicial ou dashboard, diferente do que fizemos anteriormente ao implementarmos somente as transferências.

Dashboard ou tela inicial do aplicativo Bytebank em um celular com painel lateral de ferramentas de visualização

Nesta tela, vemos dois componentes visuais: o logotipo da empresa em maior evidência e um retângulo que representa a funcionalidade de contatos. Ao clicar nesta última, acessaremos a lista e poderemos cadastrar um novo item com o formulário através do floating action button. Simularemos um cadastro inserindo o nome "Joao" no campo "Full name" e um número de conta fictício "4000" em "Account number", finalizando a tarefa com clique no botão "Create".

Tela de lista de contatos com novo contato adicionado em destaque e botão de novo cadastro "floating action button" em destaque

Este é o fluxo do nosso aplicativo; observando brevemente, não há muitas novidades visuais em relação ao que já aprendemos, mas há detalhes extras importantes que serão explorados ao longo das aulas.

No curso anterior, quando salvávamos uma informação e esta era apresentada na lista, a perdíamos quando o aplicativo era reiniciado ou fechado. Agora, aprenderemos como estes dados são armazenados no dispositivo de modo a mantê-los no app mesmo após ter sido encerrado.

Conheceremos as possibilidades para armazenar esse tipo de informação e usaremos o plugin SQFlite, o qual fornece suporte ao banco de dados SQLite por debaixo dos panos.

Aprenderemos a adicionar dependências, realizar as configurações iniciais e trabalhar com processamentos assíncronos não apenas com Future, mas também com async/await, uma alternativa de syntactic sugar ("açúcar sintático") do Future. Veremos também algumas peculiaridades nas implementações de telas, como no caso da apresentação de lista.

Diferentemente do treinamento anterior, aprenderemos que nossa tela não necessariamente precisa ser um Stateful Widget por completo para permitir a atualização de uma parte dela, algo que é possível com o FutureBuilder.

Aprenderemos várias técnicas com base na criação de um fluxo completo utilizando boas práticas, refatoração de código e assim por diante. Serão muitos desafios durante o curso, então mãos à obra!

Implementando o Dashboard - Criando o projeto

Agora que entendemos bem a necessidade do cliente, podemos começar a criar o projeto do novo aplicativo oficial da Bytebank. Essa criação será feita no IntelliJ IDEA, ainda que também seja possível fazê-la na Prompt de Comando, como demonstramos no treinamento anterior. Na tela inicial do IntellIJ, clicaremos na opção inicial de "Creat New Project" para gerar um novo projeto.

Teremos diversas opções na lista lateral da nova janela, entre elas a "Flutter", que usaremos para preparar o ambiente necessário para nosso desenvolvimento. No campo "Flutter SDK path:" mostramos onde está o SDK do Flutter dentro da máquina, o que depende de onde ele foi instalado. Após preenchermos de acordo com o local da instalação, clicaremos em "Next".

Barra lateral de opções da janela "New Project" do IntelliJ IDEA com a opção "Flutter" em destaque

Na próxima tela, precisaremos preencher os campos com as informações do projeto. No primeiro campo "Project name", vamos inserir o nome "Bytebank". Nesse momento devemos prestar atenção, pois o Flutter utiliza a linguagem Dart, cujo padrão exige que sempre iniciemos os nomes em minúsculo. Sendo assim, se colocarmos o nome "Bytebank" com B maiúsculo e tentarmos finalizar a criação, o programa exibirá uma mensagem informando que o nome do módulo é inválido. Portanto, chamaremos o projeto de"bytebank".

O próximo passo será definir o caminho no campo "Project location" com o diretório onde desejamos salvar o projeto. Já no campo "Description", estamos livres para adicionar a descrição que quisermos, como "A new Bytebank project", ou até mesmo deixá-lo em branco.

O campo seguinte, "Project type", pede a escolha do tipo de projeto a ser realizado, que no nosso caso será "Application". As demais opções servem para o desenvolvimento de algum tipo de biblioteca a ser reutilizada em outros trabalhos, por exemplo.

Logo em seguida, há a opção "Use AndroidX artifacts", que poderá ser marcada com um check para mantermos os novos artefatos da plataforma do Android. A opção "Organization", por padrão, vem marcada como "com.example", mas é necessário inserir uma organização própria. Em nosso caso, desenvolveremos para a organização alura.com.br, então escrevemos "br.com.alura", exatamente da maneira inversa ao domínio da Alura. Se você tiver um domínio, também poderá utilizá-lo seguindo essa orientação.

Em seguida, poderemos definir as linguagens que, por padrão já, estão definidas como "Kotlin" e "Swift" para as plataformas Android e iOS, respectivamente. Poderemos manter assim justamente porque não alteraremos o código, mas se em outra situação a equipe quiser manter uma linguagem específica, é possível escolher outras opções.

Esses são os campos que precisamos preencher para criarmos o projeto. As demais informações, como "Create project offline" (para evitar a necessidade de baixar dependências), são adicionais e não teremos que nos preocupar com elas no momento. Ao clicarmos em "Finish", o IntelliJ IDE começará a baixar as dependências e a configurar os arquivos para uma melhor indexação. Se ocorrer algum problema, seremos informados por meio de feedbacks.

Com tudo funcionando adequadamente e sem mensagens de erro, iniciaremos o emulador, o que é o primeiro passo para a execução do aplicativo. É possível usar o emulador criado no treinamento anterior ou qualquer um que preferir, pois não há uma restrição sobre qual exatamente deve ser usado ou quais configurações específicas ele deve ter. Mas é recomendável utilizar pelo menos a mesma versão de Android, nesse caso o "Android Emulator Pixel 2XL API 28" ou Android 9 Pie, para termos a mesma visualização ao decorrer do curso.

IntelliJ aberto com opção de emulador "Open Android Emulator: Pixel 2XL API 28" no campo "<no devices>" da barra superior de opções chamada "Flutter Device Selection"

Após a seleção do emulador, executaremos o aplicativo clicando no botão de "play" ao lado de main.dart ou por meio do atalho "Shift + F10". O aspecto visual inicialmente será o mesmo do projeto de demonstração feito no Prompt de Comando no curso anterior, seguindo o sample padrão criado quando geramos um projeto em Flutter, algo que poderá ser modificado no futuro conforme a evolução dessa ferramenta.

Finalizada a execução, o projeto inicial do Flutter - um contador de cliques em um botão - será exibido no emulador. O próximo passo será limparmos o projeto e prepararmos o ambiente para escrevermos nosso próprio código. Primeiro, limparemos todo o retorno (return) da classe MyApp. Após isso, alteraremos o nome do widget inicial de MyApp para BytebankApp.

Para prepararmos a primeira tela, retornaremos um MaterialApp() (do pacote material.dart), da mesma forma que no curso anterior, e incluiremos alguns widgets de modo a termos uma visualização. Começaremos com a propriedade home, que receberá o widget Scaffold(), no qual teremos a capacidade de colocar uma AppBar() contendo um title com o widget Text(). Nele, passaremos o texto "Dashboard".

import 'package:flutter/material.dart';

void main() => runApp(BytebankApp());

class BytebankApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Dashboard'),
        ),
      ), //Scaffold
    ); //MaterialApp
  }
}

Se executarmos o código com um Hot reload ("Ctrl + "), receberemos uma tela de erro, justamente por termos feito modificações muito significativas. Sendo assim, faremos um Hot restart ("Shift + F10"), e a tela inicial será exibida com sucesso.

01-tela

Essa primeira configuração é um preparo para executarmos os próximos passos da proposta de implementação, disponibilizada neste link.

Implementando o Dashboard - Adicionando imagem e botão de contatos

Agora que conseguimos criar todo o ambiente para nosso projeto, começaremos a implementação da primeira tela que representará o Dashboard. Nela teremos dois elementos, ou seja, dois widgets, e começaremos com o Column() - que, como aprendemos anteriormente, empilha outros elementos.

No IntelliJ, formataremos a definição da AppBar() com o atalho "Ctrl + Alt + L". Em seguida, incluiremos a propriedade body, que é o conteúdo de Scaffold(). Nele, passaremos o Column(), também do módulo MaterialApp, e usaremos a propriedade children para colocarmos cada um dos widgets. A ideia agora é incluirmos uma imagem, algo que ainda não aprendemos a fazer.

O Flutter nos disponibiliza widgets prontos que serão responsáveis pelo carregamento de imagens. Dentre as possibilidades comuns, temos quatro opções/constantes que já são fornecidas, evitando o trabalho de implementação. Dentre elas, temos: Image.network(), que carrega uma imagem online;Image.asset(), que carrega uma imagem de dentro do projeto; além de Image.file() e Image.memory(), responsáveis por carregar arquivos a partir do dispositivo ou na memória.

As abordagens mais comuns são a partir de Image.network() ou Image.asset(), e testaremos seus funcionamentos em nosso trabalho. Começando pelo primeiro, é exigido o envio de um argumento src (source), que é uma string representando o endereço da imagem online. Para testarmos, usaremos uma imagem gratuita do site http://pixabay.com, cujo endereço passaremos entre aspas simples.

class BytebankApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Dashboard'),
        ), 
        body: Column(
          children: <Widget>[
            Image.network(
                'https://cdn.pixabay.com/photo/2019/10/15/06/03/pinwheel-4550711_960_720.jpg')
          ],
        ), 
      ), 
    ); 
  }
}

Ao executarmos o Hot reload, a imagem será carregada na aplicação.

02-imagem

Porém, a equipe do Bytebank já nos enviou uma imagem própria para o aplicativo. Sendo assim, faz sentido aprendermos a abordagem com Image.asset(), que não necessita de um endereço online. Portanto, substituiremos a chamada no código.

body: Column(
  children: <Widget>[
    Image.asset()
  ], 
), 

Em seguida, precisaremos fazer uma configuração para que o Flutter encontre a imagem desejada. Em projetos Flutter, existe um arquivo, chamado pubspec.yaml, que é responsável por fazer toda a configuração do projeto, seja a configuração feita inicialmente, definição de dependências e assim por diante.

Acessaremos o pubspec.yaml na raiz do projeto e encontraremos diversas informações, como o nome do projeto, a descrição que foi atribuída, versão do Flutter, versão do SDK, entre outras. No caso da adição de assets, há uma parte com a instrução flutter na qual encontraremos alguns comentários, incluindo instruções sobre como ativar os assets. Isso na verdade é bem simples: basta "descomentarmos" o trecho referente a eles no código.

# The following line ensures that the Material Icons font is
# included with your application, so that you can use the icons in
# the material Icons class.
uses-material-design: true

# To add assets to your application, add an assets section, like this:
assets:
- images/a_dot_burr.jpeg
- images/a_dot_ham.jpeg

Recomendamos manter a indentação das configurações iniciais, da mesma forma como está o padrão de uses-material-design, pois a configuração desse arquivo é um pouco exigente e pode trazer problemas caso não seja seguida à risca.

Feita essa modificação, como o próprio IntelliJ é integrado com este arquivo, receberemos a sugestão de atualizá-lo. Clicando em "Packages get" ou "Packages upgrade" na barra de "Flutter commands" conseguiremos realizar a atualização. Ao final do processo, caso não ocorra nenhum erro, o IntelliJ exibirá um alerta de que os assets que estamos passando não existem, pois ainda não configuramos nenhum tipo de asset no projeto.

O próximo passo será criarmos o caminho apresentado para disponibilização dos assets. Na raiz do projeto, criaremos um novo diretório, chamado "images", com o atalho "Alt + Insert" e a opção "Directory". Em seguida, será necessário baixar o arquivo zipado com a imagem, disponibilizado nos exercícios do curso.

Extrairemos o arquivo bytebank_logo.png e, pelo próprio IntelliJ, o moveremos para o diretório "images" do projeto. Se você estiver usando o Git, é possível que seja exibida uma mensagem perguntando se você deseja adicionar o arquivo ao seu repositório, algo que é opcional.

Com a imagem incluída no projeto, passaremos o seu nome no caminho indicado. Para facilitar, você pode clicar sobre o arquivo no menu lateral e usar o atalho "Shift + F6" para, na janela "Rename", selecionar o seu nome e a extensão. Não devemos nos esquecer de apagar os valores padrão que não fazem sentido para o nosso projeto.

assets:
- bytebank_logo.png

Clicaremos novamente em "Packages get" para atualizar o projeto, e a mensagem de alerta deixará de ser exibida. De volta ao main.dart, recebemos outro apontamento dizendo que o Pubspec foi editado. Se clicarmos em "Get dependencies", as dependências do projeto serão atualizadas, algo que poderá evitar problemas futuros. Agora, nos falta inserir o endereço completo da imagem em Image.asset().

class BytebankApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Dashboard'),
        ), 
        body: Column(
          children: <Widget>[
            Image.asset('images/bytebank_logo.png')
          ], 
        ), 
      ), 
    ); 
  }
}

Ao fazermos o Hot reload, o emulador passará a exibir o logotipo do Bytebank.

03-logo

O próximo passo será colocarmos o botão "Contacts" que deverá figurar no canto inferior esquerdo do aplicativo. Para isso, usaremos o widget Container(), muito comum quando queremos incluir "caixas" na tela.

body: Column(
  children: <Widget>[
    Image.asset('images/bytebank_logo.png'),
    Container(),
  ], 
), 

Dentro do Container(), teremos outros dois widgets representando, respectivamente, um ícone e um texto. Sendo assim, incluiremos a propriedade child recebendo um Column() e, dentro desse widget, outra propriedade children recebendo, por sua vez, o widget Icon(). Por meio do objeto Icons conseguiremos acessar os ícones do Material design, dentre eles o people, que representa "pessoas".

body: Column(
  children: <Widget>[
    Image.asset('images/bytebank_logo.png'),
    Container(
      child: Column(
        children: <Widget>[
          Icon(Icons.people),
        ],
      ),
    ),
  ], 
), 

Executando a aplicação, o ícone será apresentado na tela do aplicativo.

04-icon

Perceba que o Container() não é apresentado, pois está em branco. Para que ele seja exibido, modificaremos o seu plano de fundo com a propriedade color e a constante Colors.green.

Container(
  color: Colors.green,
  child: Column(
    children: <Widget>[
      Icon(Icons.people),
    ],
  ),
),

Com isso, o ícone ganhará um plano de fundo verde.

05-colors

O Container() sempre crescerá com base em seu conteúdo interno. Logo, se temos apenas um ícone, seu tamanho será razoavelmente pequeno. Já se adicionarmos um widget Text() com o texto "Contacts" na sequência, sua área crescerá um pouco mais.

child: Column(
  children: <Widget>[
    Icon(Icons.people),
    Text('Contacts'),
  ],
),

Uma imagem da tela inicial do Bytebank no emulador com pequeno ícone representante de pessoas em destaque, e outra tela inicial com ícone e texto escrito "contacts" em destaque após a inserção do texto no código, mostrando a diferença do tamanho do plano de fundo dos ícones de acordo com o conteúdo

Além disso, o Container() também nos permite definir a sua altura e largura por meio das propriedades específicas height e width. Vamos testar:

Container(
  height: 120,
  width: 100,
  color: Colors.green,
  child: Column(
    children: <Widget>[
      Icon(Icons.people),
      Text('Contacts'),
    ],
  ),
),

06-hw

Interessante, não? Já aprendemos a colocar assets, começamos a construir a estrutura inicial de nosso layout e, a seguir, faremos todas as modificações necessárias para atendermos às proporções de nossa proposta de implementação.

Sobre o curso Persistência com Flutter: crie um app com armazenamento interno

O curso Persistência com Flutter: crie um app com armazenamento interno possui 167 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:

Aprenda Flutter acessando integralmente esse e outros cursos, comece hoje!

Plus

De
R$ 1.800
12X
R$109
à vista R$1.308
  • Acesso a TODOS os cursos da Alura

    Mais de 1500 cursos completamente atualizados, com novos lançamentos todas as semanas, emProgramação, Front-end, UX & Design, Data Science, Mobile, DevOps e Inovação & Gestão.

  • Alura Challenges

    Desafios temáticos para você turbinar seu portfólio. Você aprende na prática, com exercícios e projetos que simulam o dia a dia profissional.

  • Alura Cases

    Webséries exclusivas com discussões avançadas sobre arquitetura de sistemas com profissionais de grandes corporações e startups.

  • Certificado

    Emitimos certificados para atestar que você finalizou nossos cursos e formações.

Matricule-se

Pro

De
R$ 2.400
12X
R$149
à vista R$1.788
  • Acesso a TODOS os cursos da Alura

    Mais de 1500 cursos completamente atualizados, com novos lançamentos todas as semanas, emProgramação, Front-end, UX & Design, Data Science, Mobile, DevOps e Inovação & Gestão.

  • Alura Challenges

    Desafios temáticos para você turbinar seu portfólio. Você aprende na prática, com exercícios e projetos que simulam o dia a dia profissional.

  • Alura Cases

    Webséries exclusivas com discussões avançadas sobre arquitetura de sistemas com profissionais de grandes corporações e startups.

  • Certificado

    Emitimos certificados para atestar que você finalizou nossos cursos e formações.

  • Luri powered by ChatGPT

    Luri é nossa inteligência artificial que tira dúvidas, dá exemplos práticos e ajuda a mergulhar ainda mais durante as aulas. Você pode conversar com Luri até 100 mensagens por semana.

  • Alura Língua (incluindo curso Inglês para Devs)

    Estude a língua inglesa com um curso 100% focado em tecnologia e expanda seus horizontes profissionais.

Matricule-se
Conheça os Planos para Empresas

Acesso completo
durante 1 ano

Estude 24h/dia
onde e quando quiser

Novos cursos
todas as semanas