Você está na página 1de 185

Machine Translated by Google

eu
Machine Translated by Google

Sobre o Tutorial
Flutter é uma estrutura de código aberto para criar aplicativos móveis de alta qualidade e alto desempenho
em sistemas operacionais móveis - Android e iOS. Ele fornece um SDK simples, poderoso, eficiente e fácil
de entender para escrever aplicativos móveis na própria linguagem do Google, Dart.

Este tutorial aborda os fundamentos do framework Flutter, instalação do Flutter SDK, configuração do
Android Studio para desenvolver aplicativos baseados em Flutter, arquitetura do Flutter
framework e desenvolvimento de todos os tipos de aplicativos móveis usando o framework Flutter.

Público
Este tutorial foi preparado para profissionais que desejam fazer carreira na área de aplicativos móveis. Este tutorial tem como
objetivo deixá-lo confortável para começar a usar o framework Flutter e suas diversas funcionalidades.

Pré-requisitos
Este tutorial foi escrito assumindo que os leitores já estão cientes do que é um Framework e que os leitores
têm um conhecimento sólido em Programação Orientada a Objetos e conhecimentos básicos em
framework Android e programação Dart.

Se você é iniciante em algum desses conceitos, sugerimos que você leia primeiro os tutoriais relacionados
a eles, antes de começar a usar o Flutter.

Direitos autorais e isenção de responsabilidade

@Copyright 2019 por Tutorials Point (I) Unip. Ltda.

Todo o conteúdo e gráficos publicados neste e-book são propriedade da Tutorials Point (I)
Unip. Ltd. O usuário deste e-book está proibido de reutilizar, reter, copiar, distribuir ou republicar qualquer
conteúdo ou parte do conteúdo deste e-book de qualquer maneira sem o consentimento por escrito do
editor.

Nós nos esforçamos para atualizar o conteúdo do nosso site e tutoriais da forma mais oportuna e precisa
possível; no entanto, o conteúdo pode conter imprecisões ou erros. Ponto de tutoriais (I) Unip.
Ltd. não oferece nenhuma garantia quanto à precisão, atualidade ou integridade de nosso site ou de
seu conteúdo, incluindo este tutorial. Se você descobrir algum erro em nosso site ou neste tutorial,
avise-nos em contact@tutorialspoint.com

eu
Machine Translated by Google

Vibração

Índice

Sobre o Tutorial ................................................ .................................................. ...........................................eu

Público................................................. .................................................. .................................................. ......eu

Pré-requisitos.................................................. .................................................. .................................................. eu

Direitos autorais e isenção de responsabilidade................................................ .................................................. ....................................eu

Índice............................................... .................................................. ...........................................ii

1. FLUTTER – INTRODUÇÃO ............................................. .................................................. ... 1

Características do Flutter................................................... .................................................. ...........................................1

Vantagens do Flutter................................................... .................................................. ....................................2

Desvantagens do Flutter................................................. .................................................. ..................................2

2. FLUTTER – INSTALAÇÃO ............................................. .................................................. ......3

Instalação no Windows.................................................. .................................................. ...................................3

Instalação em MacOS................................................. .................................................. ....................................4

3. FLUTTER – CRIANDO APLICATIVO SIMPLES NO ANDROID STUDIO ....................................... 5

4. FLUTTER – ARQUITETURA DE APLICAÇÃO DO FLUTTER ........................................... ............. 12

Widgets.................................................. .................................................. .................................................. ....12

Gestos .................................................. .................................................. .................................................. ...13

Conceito de Estado ............................................. .................................................. ...........................................13

Camadas................................................. .................................................. .................................................. .......13

5. FLUTTER – INTRODUÇÃO À PROGRAMAÇÃO DART .......................................... ............. 15

Variáveis e tipos de dados............................................. .................................................. ................................15

Tomada de decisão e ciclos ............................................. .................................................. ...........................16

Funções................................................. .................................................. .................................................. ..16

Programação Orientada a Objetos............................................... .................................................. ......................17

6. FLUTTER – INTRODUÇÃO AOS WIDGETS ........................................... ................................ 18

eu
Machine Translated by Google

Vibração

Visualização de construção de widget ............................................. .................................................. ............................19

7. FLUTTER – INTRODUÇÃO AOS LAYOUTS ........................................... .................................. 26

Tipo de widgets de layout ............................................. .................................................. ..................................26

Widgets de filho único ............................................. .................................................. ....................................26

Vários widgets secundários ............................................. .................................................. ..................................30

Aplicação de Layout Avançado ................................................ .................................................. ........................31

8. FLUTTER – INTRODUÇÃO AOS GESTOS ........................................... ................................ 40

9. FLUTTER – GESTÃO DO ESTADO .......................................... ........................................... 45

Gerenciamento de estado efêmero ............................................. .................................................. ....................45

Estado do aplicativo - scoped_model ............................................. .................................................. .................57

Navegação e Roteamento ................................................ .................................................. ................................68

10. FLUTTER – ANIMAÇÃO ............................................. .................................................. .... 82

Introdução................................................. .................................................. ................................................82

Aulas baseadas em animação ............................................. .................................................. ..............................82

Fluxo de trabalho da Animação Flutter......................................... .................................................. .................83

Aplicação de trabalho ................................................ .................................................. ....................................84

11. FLUTTER – ESCREVER CÓDIGO ESPECÍFICO DO ANDROID ........................................... ..................... 93

12. FLUTTER – ESCREVER CÓDIGO ESPECÍFICO DO IOS ........................................... ............................ 100

13. FLUTTER – INTRODUÇÃO À EMBALAGEM ........................................... ........................... 103

Tipos de Pacotes............................................... .................................................. ........................................103

Usando um pacote Dart ............................................. .................................................. ...................................104

Desenvolva um pacote de plug-in Flutter.................................... .................................................. ..................104

14. FLUTTER – ACESSO À API REST ........................................... ........................................... 114

Conceitos Básicos................................................ .................................................. ...........................................114

Acessando a API de serviço do produto................................... .................................................. ......................115

iii
Machine Translated by Google

Vibração

15. FLUTTER – CONCEITOS DE BANCO DE DADOS .......................................... .................................... 125

SQLite ................................................ .................................................. .................................................. .....125

Nuvem Firestore ................................................ .................................................. ...........................................133

16. FLUTTER – INTERNACIONALIZAÇÃO ............................................. ................................ 138

Usando o pacote intl................................................ .................................................. ........................................143

17. FLUTTER – TESTE ............................................. .................................................. ........ 147

Tipos de testes................................................. .................................................. ...........................................147

Teste de widgets................................................ .................................................. ...........................................147

Etapas envolvidas ................................................ .................................................. ...........................................148

Exemplo de trabalho.................................................. .................................................. ........................................149

18. FLUTTER – IMPLEMENTAÇÃO ............................................. .................................................. 151

Aplicativo Android.................................................. .................................................. ...................................151

Aplicativo iOS ................................................ .................................................. ...........................................151

19. FLUTTER – FERRAMENTAS DE DESENVOLVIMENTO ............................................ .................................... 153

Conjuntos de widgets ................................................ .................................................. ................................................153

Desenvolvimento Flutter com Visual Studio Code ..................................... ....................................................153

Dart DevTools................................................. .................................................. ...........................................153

SDK do Flutter................................................... .................................................. ....................................................155

20. FLUTTER – ESCREVER APLICATIVOS AVANÇADOS ........................................... ................ 157

21. FLUTTER – CONCLUSÃO ............................................. .................................................. 180

4
Machine Translated by Google

1. Vibração – Introdução

Em geral, desenvolver uma aplicação móvel é uma tarefa complexa e desafiadora. Existem muitos
frameworks disponíveis para desenvolver um aplicativo móvel. O Android fornece uma estrutura nativa
baseada na linguagem Java e o iOS fornece uma estrutura nativa baseada na linguagem Objective-C/Shift.

No entanto, para desenvolver uma aplicação que suporte ambos os sistemas operacionais, precisamos
codificar em duas linguagens diferentes usando dois frameworks diferentes. Para ajudar a superar essa
complexidade, existem estruturas móveis que suportam ambos os sistemas operacionais. Essas estruturas
variam desde estruturas simples de aplicativos móveis híbridos baseados em HTML (que usam HTML para
interface de usuário e JavaScript para lógica de aplicativo) até estruturas complexas específicas de
linguagem (que fazem o trabalho pesado de conversão de código em código nativo). Independentemente
da sua simplicidade ou complexidade, estas estruturas têm sempre muitas desvantagens, sendo uma das
principais desvantagens o seu desempenho lento.

Nesse cenário, o Flutter – um framework simples e de alto desempenho baseado na linguagem Dart,
oferece alto desempenho ao renderizar a UI diretamente na tela do sistema operacional ao invés de através
do framework nativo.

Flutter também oferece muitos widgets (UI) prontos para usar para criar um aplicativo moderno. Esses
os widgets são otimizados para o ambiente móvel e projetar o aplicativo usando widgets é tão simples
quanto projetar HTML.

Para ser mais específico, o próprio aplicativo Flutter é um widget. Os widgets Flutter também suportam
animações e gestos. A lógica da aplicação é baseada na programação reativa. O widget pode opcionalmente
ter um estado. Ao alterar o estado do widget, o Flutter irá automaticamente (programação reativa) comparar
o estado do widget (antigo e novo) e renderizar o widget apenas com as alterações necessárias, em vez
de renderizar novamente o widget inteiro.

Discutiremos a arquitetura completa nos próximos capítulos.

Recursos do Flutter
A estrutura Flutter oferece os seguintes recursos aos desenvolvedores:

• Quadro moderno e reativo.

• Utiliza a linguagem de programação Dart e é muito fácil de aprender.


• Desenvolvimento rápido.
• Interfaces de usuário bonitas e fluidas.

• Enorme catálogo de widgets.


• Executa a mesma UI para múltiplas plataformas.
• Aplicativo de alto desempenho.

1
Machine Translated by Google

Vibração

Vantagens do Flutter
Flutter vem com widgets bonitos e personalizáveis para alto desempenho e excelente aplicativo móvel. Ele
atende a todas as necessidades e requisitos personalizados. Além dessas, o Flutter oferece muitas outras
vantagens conforme mencionado abaixo:
• O Dart possui um grande repositório de pacotes de software que permite ampliar os recursos do seu
aplicativo.

• Os desenvolvedores precisam escrever apenas uma única base de código para ambos os aplicativos
(plataformas Android e iOS). O Flutter também pode ser estendido para outras plataformas no futuro.

• Flutter precisa de menos testes. Devido à sua base de código única, é suficiente escrever testes
automatizados uma vez para ambas as plataformas.

• A simplicidade do Flutter o torna um bom candidato para desenvolvimento rápido. Sua capacidade de
personalização e extensibilidade o tornam ainda mais poderoso.

• Com o Flutter, os desenvolvedores têm controle total sobre os widgets e seu layout.

• Flutter oferece ótimas ferramentas para desenvolvedores, com incrível recarga a quente.

Desvantagens do Flutter
Apesar de suas muitas vantagens, o flutter tem as seguintes desvantagens:

• Como é codificado na linguagem Dart, um desenvolvedor precisa aprender uma nova linguagem (embora
seja fácil de aprender).

• A estrutura moderna tenta separar a lógica e a UI tanto quanto possível, mas, no Flutter, a interface do
usuário e a lógica são misturadas. Podemos superar isso usando codificação inteligente e módulo de
alto nível para separar a interface do usuário e a lógica.

• Flutter é mais uma estrutura para criar aplicativos móveis. Os desenvolvedores estão tendo dificuldade
em escolher as ferramentas de desenvolvimento certas em um segmento extremamente populoso.

2
Machine Translated by Google

2. Vibração – Instalação Vibração

Este capítulo irá guiá-lo detalhadamente pela instalação do Flutter em seu computador local.

Instalaçãono Windows
Nesta seção, vamos ver como instalar o Flutter SDK e seus requisitos em um sistema Windows.

Passo 1: Vá para URL, https://flutter.dev/docs/get-started/install/windows e baixe o Flutter SDK mais recente. Em abril de
2019, a versão é 1.2.1 e o arquivo é flutter_windows_v1.2.1-stable.zip.

Etapa 2: descompacte o arquivo zip em uma pasta, digamos C:\flutter\

Etapa 3: atualize o caminho do sistema para incluir o diretório flutter bin.

Etapa 4: Flutter fornece uma ferramenta, flutter doctor, para verificar se todos os requisitos de desenvolvimento de flutter
foram atendidos.

médico agitado

Etapa 5: A execução do comando acima analisará o sistema e mostrará seu relatório conforme mostrado abaixo:

Resumo do médico (para ver todos os detalhes, execute flutter doctor -v):
[ÿ] Flutter (canal estável, v1.2.1, no Microsoft Windows [versão 10.0.17134.706], localidade en-US)

[ÿ] Conjunto de ferramentas Android - desenvolvimento para dispositivos Android (Android SDK versão 28.0.3)

[ÿ] Android Studio (versão 3.2)


[ÿ] VS Code, edição de 64 bits (versão 1.29.1)
[!] Dispositivo conectado
! Nenhum dispositivo disponível

! O médico encontrou problemas em 1 categoria.

O relatório diz que todas as ferramentas de desenvolvimento estão disponíveis, mas o dispositivo não está conectado.
Podemos corrigir isso conectando um dispositivo Android via USB ou iniciando um emulador de Android.

Etapa 6: instale o Android SDK mais recente, se relatado pelo flutter doctor

Etapa 7: instale o Android Studio mais recente, se relatado pelo flutter doctor

Etapa 8: inicie um emulador Android ou conecte um dispositivo Android real ao sistema.

Etapa 9: Instale o plugin Flutter e Dart para Android Studio. Ele fornece um modelo de inicialização para criar um novo
aplicativo Flutter, uma opção para executar e depurar o aplicativo Flutter no próprio Android Studio, etc.,

3
Machine Translated by Google

Vibração

• Abra o Android Studio.


• Clique em Arquivo > Configurações > Plug-ins.

• Selecione o plugin Flutter e clique em Instalar.


• Clique em Sim quando solicitado a instalar o plugin Dart.
• Reinicie o estúdio Android.

Instalação em MacOS
Para instalar o Flutter no MacOS, você terá que seguir os seguintes passos:

Etapa 1: vá para o URL, https://flutter.dev/docs/get-started/install/macos e baixe o Flutter SDK mais recente. Em abril de
2019, a versão é 1.2.1 e o arquivo é flutter_macos_v1.2.1-
estável.zip.

Etapa 2: descompacte o arquivo zip em uma pasta, digamos /path/to/flutter

Etapa 3: atualize o caminho do sistema para incluir o diretório flutter bin (no arquivo ~/.bashrc).

> exportar PATH="$PATH:/caminho/para/flutter/bin"

Passo 4: Habilite o caminho atualizado na sessão atual usando o comando abaixo e verifique-o também.

fonte ~/.bashrc
fonte $HOME/.bash_profile echo
$PATH

Flutter fornece uma ferramenta, flutter doctor, para verificar se todos os requisitos de desenvolvimento de flutter foram
atendidos. É semelhante ao equivalente do Windows.

Etapa 5: Instale o XCode mais recente, se relatado pelo flutter doctor

Etapa 6: instale o Android SDK mais recente, se relatado pelo flutter doctor

Etapa 7: instale o Android Studio mais recente, se relatado pelo flutter doctor

Etapa 8: inicie um emulador de Android ou conecte um dispositivo Android real ao sistema para desenvolver um
aplicativo Android.

Passo 9: Abra o simulador iOS ou conecte um dispositivo iPhone real ao sistema para desenvolver o aplicativo iOS.

Etapa 10: Instale o plugin Flutter e Dart para Android Studio. Ele fornece o modelo de inicialização para criar um novo
aplicativo Flutter, opção para executar e depurar o aplicativo Flutter no próprio Android Studio, etc.,

• Abra o Android Studio.


• Clique em Preferências > Plug-ins.
• Selecione o plugin Flutter e clique em Instalar.
• Clique em Sim quando solicitado a instalar o plugin Dart.
• Reinicie o estúdio Android.

4
Machine Translated by Google

Vibração
3. Flutter – Criando Aplicativo Simples no
Android Studio

Neste capítulo, vamos criar um aplicativo Flutter simples para entender os fundamentos da criação de um aplicativo Flutter
no Android Studio.

Etapa 1: abra o Android Studio

Etapa 2: Criar projeto Flutter. Para isso, clique em Arquivo -> Novo -> Novo Projeto Flutter

5
Machine Translated by Google

Vibração

Etapa 3: selecione o aplicativo Flutter. Para isso, selecione Aplicativo Flutter e clique em Avançar.

Passo 4: Configure o aplicativo conforme abaixo e clique em Avançar.

• Nome do projeto: hello_app


• Caminho do Flutter SDK: <path_to_flutter_sdk>
• Localização do projeto: <path_to_project_folder> •
Descrição: aplicativo hello world baseado em Flutter

6
Machine Translated by Google

Vibração

Etapa 5: configurar o projeto.

Defina o domínio da empresa como flutterapp.tutorialspoint.com e clique em Concluir

Etapa 6: insira o domínio da empresa.

O Android Studio cria um aplicativo flutter totalmente funcional com funcionalidade mínima.
Vamos verificar a estrutura da aplicação e a seguir alterar o código para realizar nossa tarefa.

7
Machine Translated by Google

Vibração

A estrutura do aplicativo e sua finalidade são as seguintes:

Vários componentes da estrutura do aplicativo são explicados aqui:

• android - Código-fonte gerado automaticamente para criar um aplicativo Android


• ios - Código-fonte gerado automaticamente para criar aplicativo iOS
• lib - Pasta principal contendo código Dart escrito usando flutter framework

• lib/main.dart – Ponto de entrada da aplicação Flutter

• test - Pasta contendo código Dart para testar a aplicação flutter

• test/widget_test.dart - Código de exemplo

• .gitignore - arquivo de controle de versão Git

• .metadata - gerado automaticamente pelas ferramentas flutter

• .packages - gerado automaticamente para rastrear os pacotes flutter


• .iml - arquivo de projeto usado pelo Android Studio

• pubspec.yaml - Usado pelo Pub, gerenciador de pacotes Flutter

• pubspec.lock - Gerado automaticamente pelo gerenciador de pacotes Flutter, Pub

• README.md - Arquivo de descrição do projeto escrito em formato Markdown

8
Machine Translated by Google

Vibração

Etapa 7: Substitua o código dart no arquivo lib/ main.dart pelo código abaixo:

importar 'pacote:flutter/material.dart';

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

class MyApp extends StatelessWidget { // Este


widget é a raiz do seu aplicativo. @override Compilação do
widget
(contexto BuildContext) {
retornarMaterialApp(
título: 'Aplicativo de demonstração Hello World',
tema: ThemeData
(primarySwatch: Colors.blue, ),

home: MyHomePage (título: 'Página inicial'), );

}
}

class MyHomePage estende StatelessWidget


{ MyHomePage({Key key, this.title}): super(key: key);

título final da String;

@override
Widget build(BuildContext context) { return Scaffold( appBar:
AppBar( title:
Text(this.title), ), body:
Center( child: Text( 'Hello World',

), );
}
}

Vamos entender o código do dardo linha por linha.

• Linha 1: importa o pacote flutter, material. O material é um pacote flutter para criar uma interface de
usuário de acordo com as diretrizes de design de materiais especificadas pelo Android.

• Linha 3: Este é o ponto de entrada do aplicativo Flutter. Chama a função runApp e passa para ela
um objeto da classe MyApp . O objetivo da função runApp é anexar o widget fornecido à tela.

• Linha 5 - 17: Widget é usado para criar UI no framework flutter. StatelessWidget é um widget que
não mantém nenhum estado do widget. MyApp estende StatelessWidget e substitui seu método
de construção . O propósito da construção

9
Machine Translated by Google

Vibração

método é criar uma parte da UI do aplicativo. Aqui, o método build usa MaterialApp, um widget para criar a UI de
nível raiz do aplicativo. Possui três propriedades – título, tema e página inicial.

o título é o título do aplicativo.

o tema é o tema do widget. Aqui, definimos azul como a cor geral do aplicativo usando a classe ThemeData
e sua propriedade, PrimarySwatch.

o home é a UI interna do aplicativo, onde definimos outro widget,


Minha página inicial

• Linha 19 - 38: MyHomePage é igual a MyApp , exceto que retorna Scaffold


Ferramenta. Scaffold é um widget de nível superior próximo ao widget MaterialApp usado para criar
design de material em conformidade com a UI. Possui duas propriedades importantes, appBar para
mostrar o cabeçalho do aplicativo e body para mostrar o conteúdo real do aplicativo. AppBar é outro widget
para renderizar o cabeçalho do aplicativo e o usamos na propriedade appBar . Na propriedade body , usamos
o widget Center , que centraliza o widget filho. Texto é o widget final e mais interno para mostrar o texto e é
exibido no centro do

tela.

Etapa 8: Agora, execute o aplicativo usando Executar -> Executar main.dart

10
Machine Translated by Google

Vibração

Etapa 9: Por fim, a saída do aplicativo é a seguinte:

11
Machine Translated by Google

4. Flutter – Arquitetura do aplicativo Flutter Vibração

Neste capítulo, vamos discutir a arquitetura da estrutura Flutter.

Widgets
O conceito central da estrutura Flutter é No Flutter, tudo é um widget. Widgets são basicamente
componentes de interface de usuário usados para criar a interface de usuário do aplicativo.

No Flutter, o próprio aplicativo é um widget. O aplicativo é o widget de nível superior e sua UI é


construída usando um ou mais filhos (widgets), que novamente são construídos usando seus widgets
filhos. Esse recurso de composição nos ajuda a criar uma interface de usuário de qualquer complexidade.

Por exemplo, a hierarquia de widgets do aplicativo hello world (criada no capítulo anterior) é
especificada no diagrama a seguir:

Aqui merecem destaque os seguintes pontos:

12
Machine Translated by Google

Vibração

• MyApp é o widget criado pelo usuário e é construído usando o widget nativo do Flutter,
MaterialApp.

• MaterialApp possui uma propriedade home para especificar a interface do usuário da página inicial,
que é novamente um widget criado pelo usuário, MyHomePage.

• MyHomePage é construído usando outro widget nativo do flutter, Scaffold.

• O scaffold possui duas propriedades – body e appBar.

• body é usado para especificar sua interface de usuário principal e appBar é usado para especificar seu cabeçalho
interface de usuário.

• Header UI é construído usando widget nativo flutter, AppBar e Body UI são construídos usando
Widget central .

• O widget Center possui uma propriedade, Child, que se refere ao conteúdo real e é construída usando o widget Text .

Gestos
Os widgets Flutter suportam interação por meio de um widget especial, GestureDetector.
GestureDetector é um widget invisível que tem a capacidade de capturar interações do usuário, como tocar, arrastar, etc.,
de seu widget filho. Muitos widgets nativos do Flutter suportam interação por meio do uso do GestureDetector. Também
podemos incorporar recursos interativos ao widget existente, compondo-o com o widget GestureDetector . Aprenderemos os
gestos separadamente nos próximos capítulos.

Conceito de Estado
Os widgets Flutter oferecem suporte à manutenção do estado , fornecendo um widget especial, StatefulWidget.
O widget precisa ser derivado do widget StatefulWidget para oferecer suporte à manutenção do estado e todos os outros
widgets devem ser derivados do StatelessWidget. Os widgets Flutter são reativos no nativo. Isso é semelhante ao reactjs e
o StatefulWidget será renderizado automaticamente sempre que seu estado interno for alterado. A nova renderização é
otimizada encontrando a diferença entre a interface do usuário do widget antigo e o novo e renderizando apenas as
alterações necessárias.

Camadas
O conceito mais importante da estrutura Flutter é que a estrutura é agrupada em múltiplas categorias em termos de
complexidade e claramente organizada em camadas de complexidade decrescente. Uma camada é construída usando sua
camada de nível seguinte imediato. A camada superior é o widget específico para Android e iOS. A próxima camada contém
todos os widgets nativos flutuantes. A próxima camada é a camada de renderização , que é um componente de renderização
de baixo nível e renderiza tudo no aplicativo flutter. As camadas vão até o código específico da plataforma principal.

13
Machine Translated by Google

Vibração

A visão geral de uma camada no Flutter é especificada no diagrama abaixo:

Os pontos a seguir resumem a arquitetura do Flutter:


• No Flutter, tudo é um widget e um widget complexo é composto por widgets já existentes.

• Recursos interativos podem ser incorporados sempre que necessário usando o GestureDetector
ferramenta.

• O estado de um widget pode ser mantido sempre que necessário usando StatefulWidget
ferramenta.

• Flutter oferece design em camadas para que qualquer camada possa ser programada dependendo
da complexidade da tarefa.

Discutiremos todos esses conceitos em detalhes nos próximos capítulos.

14
Machine Translated by Google

5. Flutter – Introdução à programação Dart Vibração

Dart é uma linguagem de programação de uso geral de código aberto. Ele foi originalmente desenvolvido pelo Google. Dart
é uma linguagem orientada a objetos com sintaxe estilo C. Ele suporta conceitos de programação como interfaces, classes,
ao contrário de outras linguagens de programação. O Dart não oferece suporte a arrays. As coleções Dart podem ser usadas
para replicar estruturas de dados, como matrizes, genéricos e digitação opcional.

O código a seguir mostra um programa Dart simples:

vazio principal()
{
print("A linguagem Dart é fácil de aprender");
}

Variáveis e tipos de dados


A variável é chamada de local de armazenamento e os tipos de dados referem-se simplesmente ao tipo e tamanho dos dados
associados a variáveis e funções.

Dart usa a palavra-chave var para declarar a variável. A sintaxe de var é definida abaixo,

var nome = 'Dardo';

As palavras-chave final e const são usadas para declarar constantes. Eles são definidos conforme abaixo:

void main() { final a


= 12; const pi =
3,14; imprimir(uma);
imprimir(pi);

A linguagem Dart oferece suporte aos seguintes tipos de dados:

• Números: É usado para representar literais numéricos – Inteiro e Duplo.

• Strings: Representa uma sequência de caracteres. Os valores de string são especificados entre aspas simples ou duplas.

• Booleanos: o Dart usa a palavra-chave bool para representar valores booleanos – verdadeiro e falso.

• Listas e Mapas: É usado para representar uma coleção de objetos. Uma lista simples pode ser definida conforme abaixo:

void main() { var


lista = [1,2,3,4,5]; imprimir(lista);

15
Machine Translated by Google

Vibração

A lista mostrada acima produz a lista [1,2,3,4,5].

O mapa pode ser definido conforme mostrado aqui:

void main() { var


mapeamento = {'id': 1,'nome':'Dart'};
imprimir(mapeamento);
}

• Dinâmico: Se o tipo de variável não estiver definido, então seu tipo padrão é dinâmico. O
O exemplo a seguir ilustra a variável de tipo dinâmico:

void main()
{ nome dinâmico = "Dart";
imprimir(nome);
}

Tomada de decisão e ciclos


Um bloco de tomada de decisão avalia uma condição antes que as instruções sejam executadas. Dart suporta
instruções If, If..else e switch.

Loops são usados para repetir um bloco de código até que uma condição específica seja atendida. Dart suporta
para, para..in , while e do..while loops.

Vamos entender um exemplo simples sobre o uso de instruções de controle e loops:

void main()
{ for( var i = 1 ; i <= 10; i++ ) { if(i%2==0)

{
imprimir(eu);
}
}
}

O código acima imprime os números pares de 1 a 10.

Funções

Uma função é um grupo de instruções que juntas executam uma tarefa específica. Vamos dar uma olhada
uma função simples no Dart conforme mostrado aqui:

void main()
{ add(3,4);
}

void add(int a,int b) { int c;

c=a+b;
imprimir(c);
}

16
Machine Translated by Google

Vibração

A função acima adiciona dois valores e produz 7 como saída.

Programação Orientada a Objetos


Dart é uma linguagem orientada a objetos. Ele suporta recursos de programação orientada a objetos, como classes, interfaces,
etc.

Uma classe é um modelo para a criação de objetos. Uma definição de classe inclui o seguinte:

• Campos

• Getters e setters

• Construtores

• Funções

Agora, vamos criar uma classe simples usando as definições acima:

classe Funcionário {
Nome da sequência;

//método getter
String get emp_name {nome de
retorno;
}

//método setter
void set emp_name(String nome) { this.name =
nome;
}

//definição da função
resultado nulo()
{
imprimir(nome);
}

} void main() { //
criação do objeto
Funcionário emp = new Funcionário();
emp.name="funcionário1";
emp.result(); //chamada de função
}

17
Machine Translated by Google

6. Flutter – Introdução aos Widgets Vibração

Como aprendemos no capítulo anterior, widgets são tudo no framework Flutter. Já aprendemos como criar
novos widgets nos capítulos anteriores.

Neste capítulo, vamos entender o conceito real por trás da criação de widgets e os diferentes tipos de
widgets disponíveis no framework Flutter .

Vamos verificar o widget MyHomePage do aplicativo Hello World . O código para esta finalidade é fornecido
abaixo:

class MyHomePage estende StatelessWidget {


MyHomePage({chave-chave, this.title}): super(chave: chave);

título final da String;

@sobrepor
Construção de widget (contexto BuildContext) {
retornar Andaime(
appBar: AppBar(
título: Texto (este.título),
),
corpo: Centro (
filho: Texto (
'Olá Mundo',
)),
);
}
}

Aqui, criamos um novo widget estendendo StatelessWidget.

Observe que o StatelessWidget requer apenas a construção de um único método para ser implementado em
sua classe derivada. O método build obtém o ambiente de contexto necessário para construir os widgets
através do parâmetro BuildContext e retorna o widget que ele constrói.

No código, usamos title como um dos argumentos do construtor e também usamos Key como outro
argumento. O título é usado para exibir o título e a chave é usada para identificar o widget no ambiente de
construção.

Aqui, o método build chama o método build do Scaffold, que por sua vez chama o método build
método de AppBar e Center para construir sua interface de usuário.

Finalmente, o método de construção Center chama o método de construção Text .

18
Machine Translated by Google

Vibração

Para melhor compreensão, a representação visual do mesmo é apresentada a seguir:

Visualização de construção de widget

No Flutter, os widgets podem ser agrupados em várias categorias com base em seus recursos, conforme listado abaixo:

• Widgets específicos da plataforma

• Widgets de layout

• Widgets de manutenção de estado

• Widgets básicos/independentes de plataforma

Vamos discutir cada um deles em detalhes agora.

Widgets específicos da plataforma


Flutter possui widgets específicos para uma determinada plataforma - Android ou iOS.

Os widgets específicos do Android são projetados de acordo com as diretrizes de design de materiais do sistema operacional
Android. Widgets específicos do Android são chamados de widgets de materiais.

Os widgets específicos do iOS são projetados de acordo com as Diretrizes de Interface Humana da Apple e são chamados
de widgets de Cupertino .

Alguns dos widgets de materiais mais usados são os seguintes:

• Andaime

• AppBar

19
Machine Translated by Google

Vibração

• BottomNavigationBar
• TabBar
• TabBarView
• ListTile
• Botão elevado

• FloatingActionButton
• FlatButton
• IconButton

• Botão suspenso
• PopupMenuButton
• Barra de botões

• Campo de texto

• Caixa de seleção

• Rádio
• Trocar
• Controle deslizante

• Selecionadores de data e hora

• SimpleDialog •
AlertDialog

Alguns dos widgets de Cupertino mais usados são os seguintes:

• Botão Cupertino
• CupertinoPicker
• CupertinoDatePicker •
CupertinoTimerPicker
• CupertinoNavigationBar
• CupertinoTabBar
• CupertinoTabScaffold •
CupertinoTabView •
CupertinoTextField
• Diálogo Cupertino
• CupertinoDialogAction
• CupertinoFullscreenDialogTransition •
CupertinoPageScaffold
• CupertinoPageTransition
• CupertinoActionSheet
• CupertinoActivityIndicator •
CupertinoAlertDialog •
CupertinoPopupSurface

20
Machine Translated by Google

Vibração

• Cupertino Slider

Widgets de layout
No Flutter, um widget pode ser criado compondo um ou mais widgets. Para compor vários widgets em um único widget, o
Flutter fornece um grande número de widgets com recurso de layout. Por exemplo, o widget filho pode ser centralizado
usando o widget Central .

Alguns dos widgets de layout populares são os seguintes:

• Container: Uma caixa retangular decorada com widgets BoxDecoration com


fundo, borda e sombra.

• Centralizar: Centralize seu widget filho

• Linha: Dispõe seus filhos na direção horizontal.

• Coluna: Organiza seus filhos na direção vertical.

• Pilha: Organize um acima do outro.

Verificaremos os widgets de layout em detalhes na próxima Introdução aos widgets de layout


capítulo.

Widgets de manutenção de estado


No Flutter, todos os widgets são derivados de StatelessWidget ou StatefulWidget.

O widget derivado de StatelessWidget não possui nenhuma informação de estado, mas pode conter widget derivado de
StatefulWidget. A natureza dinâmica do aplicativo se dá por meio do comportamento interativo dos widgets e das mudanças
de estado durante a interação. Por exemplo, tocar em um botão de contador aumentará/diminuirá o estado interno do contador
em um e a natureza reativa do widget Flutter irá renderizar automaticamente o widget usando novas informações de estado.

Aprenderemos o conceito de widgets StatefulWidget em detalhes no próximo capítulo sobre gerenciamento de estado .

Widgets básicos/independentes de plataforma


Flutter fornece um grande número de widgets básicos para criar interfaces de usuário simples e complexas de maneira
independente de plataforma. Vamos ver alguns dos widgets básicos neste capítulo.

Texto

O widget de texto é usado para exibir um pedaço de string. O estilo da string pode ser definido usando a propriedade style e
a classe TextStyle . O código de exemplo para esta finalidade é o seguinte:

Text('Olá Mundo!', estilo: TextStyle(fontWeight: FontWeight.bold))

O widget de texto possui um construtor especial, Text.rich, que aceita o filho do tipo TextSpan
para especificar a string com estilo diferente. O widget TextSpan é de natureza recursiva e aceita TextSpan como seus filhos.
O código de exemplo para esta finalidade é o seguinte:

21
Machine Translated by Google

Vibração

Text.rich( TextSpan( filhos:


<TextSpan>[ TextSpan(text: "Olá", estilo: TextStyle(fontStyle:
FontStyle.italic)),
TextSpan(texto: "Mundo", estilo: TextStyle(fontWeight: FontWeight.bold)), ], ),

As propriedades mais importantes do widget Texto são as seguintes:

• maxLines, int: Número máximo de linhas a serem mostradas

• overflow, TextOverFlow: Especifique como o overflow visual é tratado usando


Classe TextOverFlow

• estilo, TextStyle: Especifique o estilo da string usando a classe TextStyle

• textAlign, TextAlign: Alinhamento do texto como direita, esquerda, justificar, etc., usando
Classe TextAlign

• textDirection, TextDirection: Direção do texto para fluir, da esquerda para a direita ou da direita
para a esquerda

Imagem

O widget de imagem é usado para exibir uma imagem no aplicativo. O widget de imagem fornece diferentes
construtores para carregar imagens de múltiplas fontes e são os seguintes:

• Imagem - Carregador de imagem genérico usando ImageProvider

• Image.asset - Carrega imagem dos ativos do projeto flutter

• Image.file - Carrega imagem da pasta do sistema •

Image.memory - Carrega imagem da memória •

Image.Network - Carrega imagem da rede

A opção mais fácil de carregar e exibir uma imagem no Flutter é incluir a imagem como ativos do aplicativo e
carregá-la no widget sob demanda.

• Crie uma pasta, ativos na pasta do projeto e coloque as imagens necessárias.

• Especifique os ativos no pubspec.yaml conforme mostrado abaixo:

vibração:
ativos:
- ativos/smiley.png

• Agora carregue e exiba a imagem no aplicativo.

Image.asset('assets/smiley.png')

22
Machine Translated by Google

Vibração

• O código-fonte completo do widget MyHomePage do aplicativo hello world e


o resultado é mostrado abaixo:

class MyHomePage estende StatelessWidget


{ MyHomePage({Key key, this.title}): super(key: key);

título final da String;

@override
Widget build (contexto BuildContext) { return
Scaffold( appBar:
AppBar( title:
Text(this.title), ), body:

Center( child:
Image.asset("assets/smiley.png")

), );
}

A imagem carregada é mostrada abaixo:

23
Machine Translated by Google

Vibração

As propriedades mais importantes do widget Imagem são as seguintes:

• imagem, ImageProvider: imagem real a ser carregada • largura,

duplo - Largura da imagem

• altura, duplo - Altura da imagem

• alinhamento, AlignmentGeometry - Como alinhar a imagem dentro de seus limites

Ícone

O widget de ícone é usado para exibir um glifo de uma fonte descrita na classe IconData . O código para carregar um ícone de e-
mail simples é o seguinte:

Ícone (Ícones.email)

O código-fonte completo para aplicá-lo no aplicativo hello world é o seguinte:

class MyHomePage estende StatelessWidget {


MyHomePage({chave-chave, this.title}): super(chave: chave);

título final da String;

@override
Widget build (contexto BuildContext) { return
Scaffold( appBar:
AppBar( title:
Text(this.title), ), body: Center( child:

Icon(Icons.email)

), );
}
}

24
Machine Translated by Google

Vibração

O ícone carregado é mostrado abaixo:

25
Machine Translated by Google

7. Flutter – Introdução aos Layouts Vibração

Como o conceito central do Flutter é Everything is widget, o Flutter incorpora uma funcionalidade de layout de
interface do usuário nos próprios widgets. O Flutter fornece vários widgets especialmente projetados, como
Container, Center, Align, etc., apenas com o propósito de definir o layout da interface do usuário. Widgets
construídos compondo outros widgets normalmente usam widgets de layout. Vamos aprender o conceito de
layout Flutter neste capítulo.

Tipo de LayoutWidgets
Os widgets de layout podem ser agrupados em duas categorias distintas com base em seu filho:

• Widget que suporta um único filho

• Widget com suporte para vários filhos

Vamos aprender os tipos de widgets e sua funcionalidade nas próximas seções.

Widgets para filhos únicos


Nesta categoria, os widgets terão apenas um widget como filho e cada widget terá uma funcionalidade de layout
especial.

Por exemplo, o widget Center apenas centraliza o widget filho em relação ao widget pai e o widget Container
fornece flexibilidade completa para colocá-lo filho em qualquer lugar dentro dele usando diferentes opções como
preenchimento, decoração, etc.,

Widgets filho único são ótimas opções para criar widgets de alta qualidade com funcionalidade única, como
botão, rótulo, etc.,

O código para criar um botão simples usando o widget Container é o seguinte:

class MyButton estende StatelessWidget {


MeuBotão({chave chave}): super(chave: chave);

@sobrepor
Construção de widget (contexto BuildContext) {
retornar contêiner (
decoração: const BoxDecoration(
fronteira: Fronteira(
topo: BorderSide (largura: 1,0, cor: Color (0xFFFFFFFFFF)),
esquerda: BorderSide (largura: 1,0, cor: Color (0xFFFFFFFFFF)),
direita: BorderSide (largura: 1,0, cor: Color (0xFFFF000000)),
inferior: BorderSide (largura: 1,0, cor: Color (0xFFFF000000)),
),
),
filho: Contêiner (
preenchimento: const EdgeInsets.simetric (horizontal: 20,0, vertical: 2,0),
decoração: const BoxDecoration(
fronteira: Fronteira(
topo: BorderSide (largura: 1,0, cor: Color (0xFFFFDFDFDF)),

26
Machine Translated by Google

Vibração

esquerda: BorderSide (largura: 1,0, cor: Color (0xFFFFDFDFDF)),


direita: BorderSide (largura: 1,0, cor: Color (0xFFFF7F7F7F)),
inferior: BorderSide (largura: 1,0, cor: Color (0xFFFF7F7F7F)),
),
cor: Cores.cinza,
),
filho: const Text('OK',
textAlign: TextAlign.center, estilo: TextStyle (cor:
Cores.preto)),
),
);
}
}

Aqui, usamos dois widgets – um widget Container e um widget Text . O resultado do widget é um botão personalizado
conforme mostrado abaixo:

Vamos verificar alguns dos widgets de layout filho único mais importantes fornecidos pelo Flutter:

• Preenchimento: Usado para organizar seu widget filho de acordo com o preenchimento fornecido. Aqui, o preenchimento
pode ser fornecido pela classe EdgeInsets .

• Alinhar: Alinhe seu widget filho dentro de si mesmo usando o valor da propriedade de alinhamento . O valor da propriedade
de alinhamento pode ser fornecido pela classe FractionalOffset . A classe FractionalOffset especifica os deslocamentos
em termos de distância do canto superior esquerdo.

Alguns dos valores possíveis de deslocamentos são os seguintes:

• FractionalOffset(1.0, 0.0) representa o canto superior direito.


• FractionalOffset(0.0, 1.0) representa o canto inferior esquerdo.

• Um exemplo de código sobre deslocamentos é mostrado abaixo:

Centro(
filho: Contêiner (
altura: 100,0,
largura: 100,0,
cor: Cores. amarelo,
filho: Alinhar (
alinhamento: FractionalOffset (0,2, 0,6),
filho: Contêiner (
altura: 40,0,
largura: 40,0,
cor: Cores.vermelho,
),
),
),
)

• FittedBox: dimensiona o widget filho e o posiciona de acordo com o ajuste especificado.

• AspectRatio: tenta dimensionar o widget filho para a proporção especificada

27
Machine Translated by Google

Vibração

• ConstrainedBox

• Linha de base

• FractinallySizedBox

• Altura Intrínseca

• Largura Intrínseca

• Caixa Limitada

• Fora do palco

• OverflowBox

• SizedBox

• SizedOverflowBox

• Transformar

• CustomSingleChildLayout

Nosso aplicativo Hello World usa widgets de layout baseados em materiais para projetar a página inicial.
Vamos modificar nosso aplicativo hello world para construir a página inicial usando widgets de layout básicos
conforme especificado abaixo:

• Contêiner: Widget de contêiner genérico, filho único, baseado em caixa, com alinhamento,
preenchimento, borda e margem, além de recursos avançados de estilo.

• Centro: Widget de contêiner filho simples e único, que centraliza seu widget filho.

O código modificado do widget MyHomePage e MyApp é o seguinte:

class MyApp estende StatelessWidget {


@sobrepor
Construção de widget (contexto BuildContext) {

return MyHomePage(título: "Aplicativo de demonstração Hello World");

}
}

class MyHomePage estende StatelessWidget {


MyHomePage({chave-chave, this.title}): super(chave: chave);

título final da String;

@sobrepor

Construção de widget (contexto BuildContext) {


retornar contêiner(
decoração: BoxDecoration(

28
Machine Translated by Google

Vibração

cor: Cores.branco,

),

preenchimento: EdgeInsets.all(25),

filho: Centro (filho:

Texto(
'Olá Mundo',

estilo: EstiloTexto(

cor: Cores.preto,

Espaçamento entre letras: 0,5,

tamanho da fonte: 20,

),

textDirection: TextDirection.ltr,

),

));

Aqui,

• Widget de contêiner é o widget de nível superior ou raiz. O contêiner é configurado usando propriedades
de decoração e preenchimento para fazer o layout de seu conteúdo.

• BoxDecoration possui muitas propriedades como cor, borda, etc., para decorar o Container
widget e aqui, color é usado para definir a cor do contêiner.

• o preenchimento do widget Container é definido usando a classe dgeInsets , que fornece a opção de especificar
o valor do preenchimento.

• Center é o widget filho do widget Container . Novamente, Text é filho do widget Center . Text é usado para
mostrar a mensagem e Center é usado para centralizar a mensagem de texto em relação ao widget pai,
Container.

29
Machine Translated by Google

Vibração

O resultado final do código fornecido acima é um exemplo de layout conforme mostrado abaixo:

Vários widgets filhos


Nesta categoria, um determinado widget terá mais de um widget filho e o layout de cada widget é único.

Por exemplo, o widget Row permite o layout de seus filhos na direção horizontal, enquanto o widget Coluna
permite o layout de seus filhos na direção vertical. Ao compor Linha e Coluna, widgets com qualquer nível de
complexidade podem ser construídos.

Vamos aprender alguns dos widgets usados com frequência nesta seção.

• Linha - Permite organizar seus filhos de forma horizontal.

• Coluna - Permite organizar seus filhos de forma vertical.

• ListView - Permite organizar seus filhos como lista.

• GridView - Permite organizar seus filhos como galeria.

• Expandido - Usado para fazer com que os filhos do widget Linha e Coluna ocupem o
área máxima possível.

30
Machine Translated by Google

Vibração

• Tabela - Widget baseado em tabela.

• Fluxo - Widget baseado em fluxo.

• Pilha - Widget baseado em pilha.

Aplicativo de layout avançado


Nesta seção, vamos aprender como criar uma interface de usuário complexa de listagem de produtos com design
personalizado usando widgets de layout filho únicos e múltiplos.

Para tanto, siga a sequência abaixo:

• Crie um novo aplicativo Flutter no Android Studio, product_layout_app.

• Substitua o código main.dart pelo seguinte código:

importar 'pacote:flutter/material.dart';

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

class MyApp extends StatelessWidget { // Este


widget é a raiz do seu aplicativo. @override Compilação do
widget
(contexto BuildContext) {
return MaterialApp (título:
'Flutter Demo', tema:
ThemeData
(primarySwatch: Colors.blue, ),

home: MyHomePage (título: 'Página inicial de demonstração de layout do


produto'), );
}
}

class MyHomePage estende StatelessWidget


{ MyHomePage({Key key, this.title}): super(key: key);

título final da String;

@sobrepor
Construção de widget (contexto BuildContext)
{ return Scaffold (
appBar: AppBar(título:
Texto(este.título),), corpo: Centro(filho:

Texto(
'Olá Mundo', )),

);
}
}

31
Machine Translated by Google

Vibração

• Aqui,

• Criamos o widget MyHomePage estendendo StatelessWidget em vez do StatefulWidget padrão e, em seguida,


removemos o código relevante.

• Agora, crie um novo widget, ProductBox de acordo com o design especificado conforme mostrado
abaixo:

• O código do ProductBox é o seguinte:

class ProductBox estende StatelessWidget { ProductBox({chave-


chave, este.nome, esta.descrição, este.preço, esta.imagem})
: super(chave: chave);

nome da string final;


descrição final da String; preço interno
final; imagem final da
String;

Construção de widget (contexto BuildContext) { return


Container( preenchimento:
EdgeInsets.all(2), altura: 120, filho:
Cartão( filho: Row(

mainAxisAlignment: MainAxisAlignment.spaceEvenly, filhos:


<Widget>[ Image.asset("assets/
appimages/" + image), Expanded( child: Container( padding:

EdgeInsets.all(5), child:
Column( mainAxisAlignment:

MainAxisAlignment.spaceEvenly , filhos: <Widget>[ Text(this.name, style:


TextStyle(fontWeight:
FontWeight.bold)),

Text(this.description), Text("Preço:
" + this.price.toString()), ], )))

]))); }
}

32
Machine Translated by Google

Vibração

• Observe o seguinte no código:

• ProductBox usou quatro argumentos conforme especificado abaixo:

o nome - Nome do produto

o descrição - Descrição do produto

o preço - Preço do produto

o imagem - Imagem do produto

• ProductBox usa sete widgets integrados conforme especificado abaixo:

o Contêiner

o Expandido

o Linha

o Coluna

o Cartão

o Texto

o Imagem

33
Machine Translated by Google

Vibração

• ProductBox foi projetado usando o widget mencionado acima. A organização ou hierarquia do widget é
especificada no diagrama mostrado abaixo:

• Agora, coloque alguma imagem fictícia (veja abaixo) para informações do produto na pasta de ativos do aplicativo e
configure a pasta de ativos no arquivo pubspec.yaml conforme mostrado abaixo:

ativos:
- assets/appimages/floppy.png - assets/
appimages/iphone.png - assets/appimages/
laptop.png - assets/appimages/pendrive.png
- assets/appimages/pixel.png - assets/
appimages/tablet.png

iPhone.png

34
Machine Translated by Google

Vibração

Pixel.png

Laptop.png

Tablet.png

Pendrive.png

Disquete.png
• Finalmente, use o widget ProductBox no widget MyHomePage conforme especificado abaixo:

class MyHomePage estende StatelessWidget {


MyHomePage({chave-chave, this.title}): super(chave: chave);

título final da String;

@sobrepor
Compilação de widget (contexto BuildContext)
{ return
Scaffold( appBar: AppBar(title: Text("Listagem de produtos")),
body:
ListView( ShrinkWrap: true,

35
Machine Translated by Google

Vibração

preenchimento: const EdgeInsets.fromLTRB(2.0, 10.0, 2.0, 10.0), filhos:


<Widget>[ ProductBox( nome:
"iPhone",
descrição: "iPhone
é o telefone estilista de todos os tempos", preço: 1000, imagem:
"iphone. png"),

ProductBox( nome:
"Pixel", descrição: "Pixel é o telefone com mais recursos de todos os
tempos",
preço: 800, imagem:
"pixel.png"),
ProductBox( nome:
"Laptop", descrição: "Laptop é a ferramenta de desenvolvimento mais produtiva
", preço: 2000,
imagem: "laptop.png"),

ProductBox( name:
"Tablet", description: "Tablet é o dispositivo mais útil de todos os tempos para
reunião",
preço: 1500,
imagem: "tablet.png"),

ProductBox( nome:
"Pendrive", descrição: "Pendrive é um meio de armazenamento
útil", preço:
100, imagem: "pendrive.png"),
ProductBox(
nome: "Unidade de disquete",
descrição: "A unidade de disquete é um meio de armazenamento de resgate útil",
preço: 20,
imagem: "floppy.png"),

], ));
}
}

• Aqui, usamos ProductBox como filho do widget ListView .

• O código completo (main.dart) do aplicativo de layout do produto


(product_layout_app) é o seguinte:

importar 'pacote:flutter/material.dart';

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

class MyApp extends StatelessWidget { // Este


widget é a raiz do seu aplicativo. @override Compilação do
widget
(contexto BuildContext) {
return MaterialApp( título:
'Flutter Demo', tema:

ThemeData( primárioSwatch: Colors.blue,

36
Machine Translated by Google

Vibração

),
home: MyHomePage(title: 'Página inicial de demonstração de layout do produto'), );

}
}

class MyHomePage estende StatelessWidget {


MyHomePage({chave-chave, this.title}): super(chave: chave);

título final da String;

@override
Widget build (contexto BuildContext) { return
Scaffold( appBar:
AppBar(title: Text("Listagem de produtos")), body:
ListView( ShrinkWrap:
true, padding: const
EdgeInsets.fromLTRB(2.0, 10.0, 2.0, 10.0) , filhos: <Widget>[ ProductBox( nome:
"iPhone", descrição:
"iPhone é o
telefone estilista de
todos os tempos", preço: 1000, imagem: "iphone.png"),

ProductBox( nome:
"Pixel", descrição: "Pixel é o telefone com mais recursos de todos os tempos",
preço: 800,
imagem: "pixel.png"),

ProductBox( nome:
"Laptop", descrição: "Laptop é a ferramenta de desenvolvimento mais produtiva
", preço: 2000,
imagem: "laptop.png"),

ProductBox( name:
"Tablet", description: "Tablet é o dispositivo mais útil de todos os tempos para
reunião",
preço: 1500,
imagem: "tablet.png"),

ProductBox( nome:
"Pendrive", descrição: "Pendrive é um meio de armazenamento útil",
preço: 100,
imagem: "pendrive.png"),
ProductBox(
nome: "Unidade de disquete",
descrição: "A unidade de disquete é um meio de armazenamento de resgate útil",
preço: 20,
imagem: "floppy.png"),

], ));
}
}

37
Machine Translated by Google

Vibração

class ProductBox estende StatelessWidget


{ ProductBox({chave-chave, este.nome, esta.descrição, este.preço, esta.imagem})
: super(chave: chave);

nome da string final;


descrição final da String; preço
interno final; imagem
final da String;

Construção de widget (contexto BuildContext)


{ return
Container( preenchimento:
EdgeInsets.all(2),
altura: 120,
filho: Cartão( filho: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly, filhos:
<Widget>[
Image.asset("assets/appimages/" + imagem),

Expanded( child:
Container( padding: EdgeInsets.all(5),
child:
Column( mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children:

<Widget>[ Text(this.name , estilo: TextStyle(fontWeight:


Intensidade da fonte: Negrito)),
Text(this.description),
Text("Preço: " + this.price.toString()), ], )))

])));
}
}

38
Machine Translated by Google

Vibração

O resultado final do aplicativo é o seguinte:

39
Machine Translated by Google

8. Flutter – Introdução aos Gestos Vibração

Os gestos são principalmente uma forma de um usuário interagir com um aplicativo móvel (ou qualquer
dispositivo baseado em toque). Gestos são geralmente definidos como qualquer ação/movimento físico de
um usuário na intenção de ativar um controle específico do dispositivo móvel. Os gestos vão desde tocar
na tela do dispositivo móvel até ações mais complexas usadas em aplicativos de jogos.

Alguns dos gestos amplamente utilizados são mencionados aqui:

• Toque: Tocar a superfície do dispositivo com a ponta do dedo por um curto período e depois
liberando a ponta do dedo.

• Toque duplo: Tocar duas vezes em um curto espaço de tempo.

• Arrastar: Tocar a superfície do dispositivo com a ponta do dedo e depois mover a ponta do dedo de
maneira constante e finalmente soltar a ponta do dedo.

• Flick: Semelhante a arrastar, mas de forma mais rápida.

• Beliscar: Beliscar a superfície do dispositivo usando dois dedos.

• Espalhar/Zoom: Oposto de beliscar.

• Panorâmica: Tocar a superfície do dispositivo com a ponta do dedo e movê-lo em qualquer direção
sem soltar a ponta do dedo.

Flutter oferece um excelente suporte para todos os tipos de gestos através de seu widget exclusivo,
GestureDetector. GestureDetector é um widget não visual usado principalmente para detectar o gesto do
usuário. Para identificar um gesto direcionado a um widget, o widget pode ser colocado dentro do widget
GestureDetector. O GestureDetector irá capturar o gesto e enviar vários eventos com base no gesto.

Alguns dos gestos e os eventos correspondentes são apresentados a seguir:

• Toque

o onTapDown

o onTapUp

o onTap

o onTapCancel

• Toque duas vezes

o onDoubleTap

• Pressão longa

o onLongPress

40
Machine Translated by Google

Vibração

• Arrastar verticalmente

o onVerticalDragStart

o onVerticalDragUpdate

oonVerticalDragEnd

• Arrastar horizontalmente

o onHorizontalDragStart

o onHorizontalDragUpdate

o onHorizontalDragEnd

• Panela

o onPanStart

o onPanUpdate

o onPanEnd

Agora, vamos modificar o aplicativo hello world para incluir o recurso de detecção de gestos e tentar entender o conceito.

• Altere o conteúdo do corpo do widget MyHomePage conforme mostrado abaixo:

corpo: Center( filho:


GestureDetector( onTap: ()

{ _showDialog(context);
},
filho: Texto(
'Olá Mundo',
)
)
),

• Observe que aqui colocamos o widget GestureDetector acima do texto


widget na hierarquia de widgets, capturou o evento onTap e finalmente mostrou uma janela de diálogo.

• Implemente a função *_showDialog* para apresentar uma caixa de diálogo quando o usuário tabula a mensagem hello
world . Ele usa os widgets showDialog e AlertDialog genéricos para criar um novo widget de diálogo. O código
é mostrado abaixo:

// função definida pelo usuário void


_showDialog(BuildContext context) { // função definida por
flutter showDialog( context: context,
builder:
(BuildContext context)
{ // retorna objeto do tipo Dialog

41
Machine Translated by Google

Vibração

return AlertDialog( título:


new Text("Mensagem"), conteúdo: new
Text("Olá Mundo"), ações: <Widget>[ new
FlatButton( filho: new
Text("Fechar"),
onPressed: () { Navigator.

of(contexto).pop(); }, ), ], ); }, ); }

• O aplicativo será recarregado no dispositivo usando o recurso Hot Reload . Agora, basta clicar na mensagem Hello World
e aparecerá a caixa de diálogo abaixo:

• Agora, feche a caixa de diálogo clicando na opção fechar na caixa de diálogo.

42
Machine Translated by Google

Vibração

• O código completo (main.dart) é o seguinte:

importar 'pacote:flutter/material.dart';

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

class MyApp extends StatelessWidget { // Este widget


é a raiz do seu aplicativo. @override Compilação do widget (contexto
BuildContext)
{
retornarMaterialApp(
título: 'Aplicativo de demonstração Hello World', tema:
ThemeData
(primarySwatch: Colors.blue, ), home:

MyHomePage (título: 'Página inicial'), );

}
}

class MyHomePage estende StatelessWidget {


MyHomePage({chave-chave, this.title}): super(chave: chave);

título final da String;

// função definida pelo usuário void


_showDialog(BuildContext context) { // função definida por
vibração showDialog( context: context,
builder:
(BuildContext context)
{ // retorna objeto do tipo Dialog return
AlertDialog( title: new Text("Message"),
conteúdo: new Text("Olá
Mundo"), ações: <Widget>[ new
FlatButton( filho: new Text("Fechar"), onPressed:
() {

Navigator.of(context).pop(); }, ), ], ); }, );

@override
Widget build (contexto BuildContext) { return
Scaffold( appBar:
AppBar( title:
Text(this.title), ),

43
Machine Translated by Google

Vibração

corpo: Center( filho:


GestureDetector( onTap: ()

{ _showDialog(context); }, filho:

Text(
'Olá Mundo', ))),

);
}
}

Finalmente, o Flutter também fornece um mecanismo de detecção de gestos de baixo nível por meio do widget Listener . Ele
detectará todas as interações do usuário e então despachará os seguintes eventos:

• Evento PointerDown

• PointerMoveEvent

• PointerUpEvent

• PointerCancelEvent

O Flutter também fornece um pequeno conjunto de widgets para realizar gestos específicos e avançados.
Os widgets estão listados abaixo:

• Dispensar: Suporta gesto de movimento para dispensar o widget.

• Arrastável: Suporta gesto de arrastar para mover o widget.

• LongPressDraggable: Suporta gesto de arrastar para mover um widget, quando seu pai
widget também pode ser arrastado.

• DragTarget: Aceita qualquer widget arrastável .

• IgnorePointer: Oculta o widget e seus filhos da detecção de gestos


processo.

• AbsorbPointer: interrompe o próprio processo de detecção de gestos e, portanto, qualquer widget sobreposto também
não poderá participar do processo de detecção de gestos e, portanto, nenhum evento será gerado.

• Rolável: Suporta rolagem do conteúdo disponível dentro do widget

44
Machine Translated by Google

Vibração
9. Flutter – Gestão do Estado

Gerenciar o estado de um aplicativo é um dos processos mais importantes e necessários no ciclo de vida de um aplicativo.

Consideremos uma aplicação simples de carrinho de compras.

• O usuário fará login usando suas credenciais no aplicativo.

• Depois que o usuário estiver logado, o aplicativo deverá persistir os detalhes do usuário logado em todos
a tela.

• Novamente, quando o usuário seleciona um produto e o salva em um carrinho, as informações do carrinho devem
persistir entre as páginas até que o usuário faça check-out do carrinho.

• As informações do usuário e de seu carrinho em qualquer instância são chamadas de estado do aplicativo
naquela instância.

Um gerenciamento de estado pode ser dividido em duas categorias com base na duração que o estado específico dura em
um aplicativo.

• Efêmero - Dura alguns segundos, como o estado atual de uma animação, ou uma única página, como a classificação
atual de um produto. Flutter oferece suporte por meio do StatefulWidget.

• estado do aplicativo - último para todo o aplicativo, como detalhes do usuário conectado, informações do carrinho,
etc., o Flutter oferece suporte por meio de scoped_model.

Gerenciamento de estado efêmero


Como a aplicação Flutter é composta por widgets, o gerenciamento do estado também é feito por widgets. O ponto de
entrada da gestão estadual é Statefulwidget. O widget pode ser herdado do Statefulwidget para manter seu estado e o
estado de seus filhos. Widget com estado
fornece uma opção para um widget criar um estado, State<T> (onde T é o widget herdado) quando o widget é criado pela
primeira vez por meio do método createState e, em seguida, um método, setState para alterar o estado sempre que
necessário. A mudança de estado será feita através de gestos. Por exemplo, a avaliação de um produto pode ser alterada
tocando em uma estrela no widget de avaliação.

Vamos criar um widget, RatingBox com manutenção de estado. O objetivo do widget é mostrar a classificação atual de um
produto específico. O processo passo a passo para criar um widget RatingBox com manutenção de estado é o seguinte:

• Crie o widget RatingBox herdando StatefulWidget

class RatingBox estende StatefulWidget {


}

• Crie um estado para RatingBox, _RatingBoxState herdando State<T>

classe _RatingBoxState estende State<RatingBox> {


}

45
Machine Translated by Google

Vibração

• Substitua o método createState do StatefulWidget para criar o estado,


_RatingBoxState

class RatingBox estende StatefulWidget { @override

_RatingBoxState createState() => _RatingBoxState();


}

Crie a interface do usuário do widget RatingBox no método de construção de _RatingBoxState.


Normalmente, a interface do usuário será feita no método de construção do próprio widget RatingBox. Mas, quando a manutenção
do estado é necessária, precisamos construir a interface do usuário no widget _RatingBoxState. Isso garante a nova renderização
da interface do usuário sempre que o estado do widget for alterado.

Construção de widget (contexto BuildContext) {


duplo _tamanho = 20;
imprimir(_classificação);

return
Row( mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.end, mainAxisSize:
MainAxisSize.max, filhos:

<Widget>[ Container( preenchimento:


EdgeInsets.all(0), filho: IconButton(
ícone: (_rating >= 1 ? Ícone (Icons.star, tamanho: _size,): Ícone (Icons.star_border,
tamanho: _size,)), cor: Colors.red[500], iconSize: _size, ), ),
Container( preenchimento:
EdgeInsets.all(0), filho:

IconButton(

ícone: (_rating >= 2 ? Ícone (Icons.star, tamanho: _size,): Ícone (Icons.star_border,


tamanho: _size,)), cor: Colors.red[500], iconSize: _size, ), ),
Container( preenchimento:
EdgeInsets.all(0), filho:

IconButton(

ícone: (_rating >= 3 ? Ícone (Icons.star, tamanho: _size,): Ícone (Icons.star_border,


tamanho: _size,)), cor: Colors.red[500], iconSize: _size, ), ),

], );
}

46
Machine Translated by Google

Vibração

Aqui, usamos três estrelas, criadas usando o widget IconButton e organizadas usando o widget Row em uma única linha. A ideia
é mostrar a classificação através da sequência de estrelas vermelhas.
Por exemplo, se a classificação for de duas estrelas, as duas primeiras estrelas serão vermelhas e a última será branca.

• Escreva métodos em _RatingBoxState para alterar/definir o estado do widget.

void _setRatingAsOne() { setState( ()


{ _rating = 1; });

void _setRatingAsTwo() {

setState( ()
{ _classificação =
2; });
}

void _setRatingAsThree() { setState( ()


{ _rating = 3; });

• Aqui, cada método define a classificação atual do widget por meio de setState

• Conecte o gesto do usuário (tocar na estrela) ao método de mudança de estado adequado.

Construção de widget (contexto BuildContext) {


duplo _tamanho = 20;
imprimir(_classificação);

return
Row( mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.end, mainAxisSize:
MainAxisSize.max, filhos:

<Widget>[ Container( preenchimento:


EdgeInsets.all(0), filho: IconButton(
ícone: (_rating> = 1? Ícone (Icons.star, tamanho: _size,): Ícone (Icons.star_border,
tamanho: _size,)), cor: Colors.red [500], onPressed:
_setRatingAsOne, iconSize:
_size, ), ), Container( preenchimento:
EdgeInsets.all(0), filho:

IconButton(

ícone: (_rating >= 2 ? Ícone (Icons.star, tamanho: _size,): Ícone (Icons.star_border,


tamanho: _size,)), cor: Colors.red[500],

47
Machine Translated by Google

Vibração

onPressed: _setRatingAsTwo, iconSize:


_size, ), ),

Container( preenchimento: EdgeInsets.all(0),


filho: IconButton(
ícone: (_rating> = 3? Ícone (Icons.star, tamanho: _size,): Ícone (Icons.star_border,
tamanho: _size,)), cor: Colors.red [500], onPressed:
_setRatingAsThree, iconSize:
_size, ), ),

], );
}

Aqui, o evento onPressed chama a função relevante para alterar o estado e posteriormente alterar a interface do usuário. Por
exemplo, se um usuário clicar na terceira estrela, _setRatingAsThree será chamado e mudará _rating para 3. Como o estado foi
alterado, o método build será chamado novamente e a interface do usuário será construída e renderizada novamente.

• O código completo do widget RatingBox é o seguinte:

class RatingBox estende StatefulWidget { @override

_RatingBoxState createState() => _RatingBoxState();


}

classe _RatingBoxState estende State<RatingBox> {


int _classificação = 0;

void _setRatingAsOne() { setState( ()


{ _rating = 1; });

void _setRatingAsTwo() {

setState( ()
{ _classificação =
2; });
}

void _setRatingAsThree() { setState( ()


{ _rating = 3; });

Construção de widget (contexto BuildContext) {

48
Machine Translated by Google

Vibração

duplo _tamanho = 20;


imprimir(_classificação);

return
Row( mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.end, mainAxisSize:
MainAxisSize.max, filhos:

<Widget>[ Container( preenchimento:


EdgeInsets.all(0), filho: IconButton(
ícone: (_rating> = 1? Ícone (Icons.star, tamanho: _size,): Ícone (Icons.star_border,
tamanho: _size,)), cor: Colors.red [500], onPressed:
_setRatingAsOne, iconSize:
_size, ), ), Container( preenchimento:
EdgeInsets.all(0), filho:

IconButton(

ícone: (_rating >= 2? Ícone (Icons.star, tamanho: _size,): Ícone (Icons.star_border,


tamanho: _size,)), cor: Colors.red[500], onPressed:
_setRatingAsTwo, iconSize:
_size, ), ), Container( preenchimento:
EdgeInsets.all(0), filho:

IconButton(

ícone: (_rating> = 3? Ícone (Icons.star, tamanho: _size,): Ícone (Icons.star_border,


tamanho: _size,)), cor: Colors.red [500], onPressed:
_setRatingAsThree, iconSize:
_size, ), ),

], );
}
}

Vamos criar um novo aplicativo e usar nosso widget RatingBox recém-criado para mostrar a classificação do produto.

• Crie um novo aplicativo Flutter no Android Studio, product_state_app

Substitua o código main.dart pelo código abaixo:

importar 'pacote:flutter/material.dart';

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

49
Machine Translated by Google

Vibração

class MyApp extends StatelessWidget { // Este


widget é a raiz do seu aplicativo. @override Compilação do
widget
(contexto BuildContext) {
return MaterialApp (título:
'Flutter Demo', tema:
ThemeData
(primarySwatch: Colors.blue, ),

home: MyHomePage (título: 'Página inicial de demonstração do estado do


produto'), );
}
}

class MyHomePage estende StatelessWidget


{ MyHomePage({Key key, this.title}): super(key: key);

título final da String;

@override
Widget build (contexto BuildContext) { return Scaffold( appBar:
AppBar( title:
Text(this.title), ), body:
Center( child:

Texto(
'Olá Mundo', )),

);
}
}

• Aqui,

• Criamos o widget MyHomePage estendendo StatelessWidget em vez de


padrão StatefulWidget e, em seguida, removeu o código relevante.

• Incluir nosso widget RatingBox recém-criado.

• Crie um widget ProductBox para listar o produto junto com a classificação conforme especificado abaixo:

class ProductBox estende StatelessWidget


{ ProductBox({Key key, this.name, this.description, this.price, this.image}): super(key:
key);

nome da string final;


descrição final da String; preço
interno final; imagem
final da String;

Construção de widget (contexto BuildContext)


{ return Container (

50
Machine Translated by Google

Vibração

preenchimento: EdgeInsets.all(2),
altura: 120, filho:
Card( filho: Row(

mainAxisAlignment: MainAxisAlignment.spaceEvenly, filhos:


<Widget>[
Image.asset("assets/appimages/" + imagem),

Expanded( child:
Container( padding: EdgeInsets.all(5),
child:
Column( mainAxisAlignment:
MainAxisAlignment.spaceEvenly,
filhos:

<Widget>[ Text(this.name, style: TextStyle(fontWeight:


Intensidade da fonte: Negrito)),
Text(this.description),
Text("Preço: " + this.price.toString()), RatingBox(), ], )))

])));
}
}

• Atualize o widget MyHomePage para incluir o widget ProductBox conforme especificado


abaixo:

class MyHomePage estende StatelessWidget


{ MyHomePage({Key key, this.title}): super(key: key);

título final da String;

@override
Widget build (contexto BuildContext) { return
Scaffold( appBar:
AppBar(title: Text("Listagem de produtos")), body:
ListView( ShrinkWrap:
true, padding: const
EdgeInsets.fromLTRB(2.0, 10.0, 2.0, 10.0) , filhos: <Widget>[ ProductBox( nome:
"iPhone", descrição:
"iPhone é o
telefone estilista de
todos os tempos", preço: 1000, imagem: "iphone.png"),
ProductBox( nome:
"Pixel", descrição: " Pixel é
o telefone com
mais recursos de
todos os tempos", preço: 800, imagem: "pixel.png"), ProductBox( nome:
"Laptop",
descrição: "Laptop é a
ferramenta de
desenvolvimento
mais produtiva",

51
Machine Translated by Google

Vibração

preço: 2000,
imagem: "laptop.png"),

ProductBox( name:
"Tablet", description: "Tablet é o dispositivo mais útil de todos os tempos para
reunião",
preço: 1500,
imagem: "tablet.png"),

ProductBox( nome:
"Pendrive", descrição: "Pendrive é um meio de armazenamento
útil", preço:
100, imagem: "pendrive.png"),
ProdutoCaixa(
name: "Unidade de disquete",
description: "A unidade de disquete é um armazenamento de resgate útil
médio",
preço: 20,
imagem: "floppy.png"),

], ));
}
}

• O código completo da aplicação é o seguinte:

importar 'pacote:flutter/material.dart';

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

class MyApp extends StatelessWidget { // Este


widget é a raiz do seu aplicativo. @override Compilação do
widget
(contexto BuildContext) {
return MaterialApp (título:
'Flutter Demo', tema:
ThemeData
(primarySwatch: Colors.blue, ),

home: MyHomePage (título: 'Página inicial de demonstração de layout do


produto'), );
}
}

class MyHomePage estende StatelessWidget


{ MyHomePage({Key key, this.title}): super(key: key);

título final da String;

@sobrepor
Compilação de widget (contexto BuildContext)
{ return
Scaffold( appBar: AppBar(title: Text("Listagem de produtos")),
body: ListView(

52
Machine Translated by Google

Vibração

ShrinkWrap: true,
preenchimento: const EdgeInsets.fromLTRB(2.0, 10.0, 2.0, 10.0), filhos:
<Widget>[ ProductBox( nome:
"iPhone",
descrição: "iPhone
é o telefone estilista de todos os tempos", preço: 1000, imagem :
"iphone.png"),

ProductBox( nome:
"Pixel", descrição: "Pixel é o telefone com mais recursos de todos os
tempos",
preço: 800, imagem:
"pixel.png"),
ProductBox( nome:
"Laptop", descrição: "Laptop é a ferramenta de desenvolvimento mais produtiva
", preço: 2000,
imagem: "laptop.png"),

ProductBox( name:
"Tablet", description: "Tablet é o dispositivo mais útil de todos os tempos para
reunião",
preço: 1500,
imagem: "tablet.png"),

ProductBox( nome:
"Pendrive", descrição: "iPhone é o telefone estilista de todos os
tempos",
preço: 100, imagem:
"pendrive.png"), ProductBox(
nome: "Floppy Drive",
descrição: "iPhone é o telefone estilista de todos os tempos",
preço: 20,
imagem: "floppy.png"),

ProductBox(nome:
"iPhone", descrição: "iPhone é o telefone estilista de todos os
tempos", preço:
1000, imagem: "iphone.png"),

ProductBox(nome:
"iPhone", descrição: "iPhone é o telefone estilista de todos os
tempos", preço:
1000, imagem: "iphone.png"),

], ));
}
}

class RatingBox estende StatefulWidget { @override

_RatingBoxState createState() => _RatingBoxState();


}

classe _RatingBoxState estende State<RatingBox> {

53
Machine Translated by Google

Vibração

int _classificação = 0;

void _setRatingAsOne() { setState( ()


{ _rating = 1; });

void _setRatingAsTwo() {

setState( ()
{ _classificação =
2; });
}

void _setRatingAsThree() { setState( ()


{ _rating = 3; });

Construção de widget (contexto BuildContext) {


duplo _tamanho = 20;
imprimir(_classificação);

return
Row( mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.end, mainAxisSize:
MainAxisSize.max, filhos:

<Widget>[ Container( preenchimento:


EdgeInsets.all(0), filho: IconButton(
ícone: (_rating> = 1? Ícone (Icons.star, tamanho: _size,): Ícone (Icons.star_border,
tamanho: _size,)), cor: Colors.red [500], onPressed:
_setRatingAsOne, iconSize:
_size, ), ), Container( preenchimento:
EdgeInsets.all(0), filho:

IconButton(

ícone: (_rating >= 2? Ícone (Icons.star, tamanho: _size,): Ícone (Icons.star_border,


tamanho: _size,)), cor: Colors.red[500], onPressed:
_setRatingAsTwo, iconSize:
_size, ), ), Container( preenchimento:
EdgeInsets.all(0), filho:

IconButton(

ícone: (_rating >= 3 ? Ícone (Icons.star, tamanho: _size,): Ícone (Icons.star_border,


tamanho: _size,)),

54
Machine Translated by Google

Vibração

color: Colors.red[500],
onPressed: _setRatingAsThree,
iconSize: _size, ), ),

], );
}
}

class ProductBox estende StatelessWidget


{ ProductBox({Key key, this.name, this.description, this.price, this.image}):
super(key: key);

nome da string final;


descrição final da String; preço
interno final; imagem
final da String;

Construção de widget (contexto BuildContext)


{ return
Container( preenchimento:
EdgeInsets.all(2),
altura: 140,
filho: Cartão( filho: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly, filhos:
<Widget>[
Image.asset("assets/appimages/" + imagem),

Expanded( child:
Container( padding: EdgeInsets.all(5),
child:
Column( mainAxisAlignment:
MainAxisAlignment.spaceEvenly,
filhos:

<Widget>[ Text(this.name, style: TextStyle(fontWeight:


Intensidade da fonte: Negrito)),
Text(this.description),
Text("Preço: " + this.price.toString()), RatingBox(), ], )))

])));
}
}

55
Machine Translated by Google

Vibração

• Por fim, execute o aplicativo e consulte a página Gerenciamento de estado - Lista de produtos
Resultados conforme mostrado aqui:

56
Machine Translated by Google

Vibração

Clicar na estrela de avaliação atualizará a avaliação do produto. Por exemplo, definir 2 estrelas
a classificação para iPhone exibirá a classificação conforme abaixo:

Estado do aplicativo -scoped_model


Flutter fornece uma maneira fácil de gerenciar o estado do aplicativo usando scoped_model
pacote. O pacote Flutter é simplesmente uma biblioteca de funcionalidades reutilizáveis. Aprenderemos
sobre os pacotes Flutter em detalhes nos próximos capítulos.

scoped_model fornece três classes principais para permitir o gerenciamento robusto de estado em um
aplicativo, que são discutidas em detalhes aqui:

Modelo
O modelo encapsula o estado de um aplicativo. Podemos usar quantos Model (herdando a classe Model)
forem necessários para manter o estado do aplicativo. Possui um único método, notifyListeners, que precisa
ser chamado sempre que o estado do Model muda. notifyListeners fará as coisas necessárias para atualizar
a IU.

classe Produto estende Modelo {


nome da string final;
descrição final da String;
preço interno final;

57
Machine Translated by Google

Vibração

imagem final da String;


classificação interna;

Produto(este.nome, esta.descrição, este.preço, esta.imagem, esta.classificação);

fábrica Product.fromMap(Map<String, dynamic> json) { return


Product( json['nome'],
json['descrição'],
json['preço'], json['imagem'],
json['classificação' ], );

void updateRating(int minhaRating) {


classificação = minhaclassificação;

notificarListeners();
}
}

Modelo com escopo

ScopedModel é um widget que contém o modelo fornecido e o passa para todos os widgets descendentes, se
solicitado. Se for necessário mais de um modelo, precisaremos aninhar o ScopedModel.

• Modelo único

ScopedModel<Produto>( modelo:
item, filho:
AnyWidget()
)

• Modelo múltiplo

ScopedModel<Produto>( modelo:
item1, filho:
ScopedModel<Produto>( modelo:
item2, filho:
AnyWidget(), ),

ScopedModel.of é um método usado para obter o modelo subjacente ao ScopedModel. Ele pode ser usado
quando nenhuma alteração na interface do usuário for necessária, mesmo que o modelo seja alterado. O
seguinte não alterará a UI (classificação) do produto.

ScopedModel.of<Produto>(context).updateRating(2);

58
Machine Translated by Google

Vibração

ScopedModelDescendente
ScopedModelDescendant é um widget que obtém o modelo do widget de nível superior, ScopedModel, e constrói sua
interface de usuário sempre que o modelo muda.

ScopedModelDescendant tem duas propriedades – construtor e filho. child é a parte da UI que não muda e será
passada para o construtor. construtor aceita uma função com três argumentos:

• content - ScopedModelDescendant passa o contexto da aplicação.

• filho - Uma parte da UI, que não muda com base no modelo.
• model - O modelo real naquela instância.

return ScopedModelDescendant<ProductModel>(
construtor: (contexto, filho, carrinho) => { ... UI real ... }, filho: PartOfTheUI(), );

Vamos alterar nosso exemplo anterior para usar scoped_model em vez de StatefulWidget

• Crie um novo aplicativo Flutter no Android Studio, product_scoped_model_app

• Substitua o código de inicialização padrão (main.dart) pelo nosso código product_state_app.

• Copie a pasta de ativos de product_nav_app para product_rest_app e adicione ativos


dentro do arquivo pubspec.yaml

vibração:

ativos:
- assets/appimages/floppy.png - assets/
appimages/iphone.png - assets/appimages/
laptop.png - assets/appimages/pendrive.png
- assets/appimages/pixel.png - assets/
appimages/tablet.png

• Configure o pacote scoped_model no arquivo pubspec.yaml conforme mostrado abaixo:

dependências:
modelo_com escopo: ^1.0.1

Aqui, você deve usar a versão mais recente do pacote http

• O Android Studio alertará que o pubspec.yaml foi atualizado.

• Clique na opção Obter dependências. O Android Studio obterá o pacote da Internet e o configurará
adequadamente para o aplicativo.

59
Machine Translated by Google

Vibração

• Substitua o código de inicialização padrão (main.dart) pelo nosso código de inicialização.

importar 'pacote:flutter/material.dart';

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

class MyApp extends StatelessWidget { // Este


widget é a raiz do seu aplicativo. @override Compilação do
widget
(contexto BuildContext) {
return MaterialApp (título:
'Flutter Demo', tema:
ThemeData
(primarySwatch: Colors.blue, ),

home: MyHomePage (título: 'Página inicial de demonstração do estado do


produto'), );
}
}

class MyHomePage estende StatelessWidget


{ MyHomePage({Key key, this.title}): super(key: key);

título final da String;

@override
Widget build (contexto BuildContext) { return Scaffold( appBar:
AppBar( title:
Text(this.title), ), body:
Center( child: Text( 'Hello World', )),

);
}
}

• Importe o pacote scoped_model no arquivo main.dart

importar 'pacote:scoped_model/scoped_model.dart';

• Vamos criar uma classe Product, Product.dart para organizar as informações do produto.

importar 'pacote:scoped_model/scoped_model.dart';

class Produto estende Modelo { final


String nome; descrição
final da String; preço interno final;
imagem final da
String; classificação
interna;

60
Machine Translated by Google

Vibração

Produto (este.nome, esta.descrição, este.preço, esta.imagem,


esta.classificação);

fábrica Product.fromMap(Map<String, dynamic> json) { return


Product( json['nome'],
json['descrição'],
json['preço'], json['imagem'],
json['classificação' ], );

void updateRating(int minhaRating) {


classificação = minhaclassificação;

notificarListeners();
}
}

Aqui, usamos notifyListeners para alterar a IU sempre que a classificação é alterada.

• Vamos escrever um método getProducts na classe Product para gerar nosso modelo
registros do produto.

static List<Produto> getProdutos() {


List<Produto> itens = <Produto>[];

items.add(Product( "Pixel",
"Pixel é o
telefone com mais recursos de todos os tempos", 800,

"pixel.png", 0));

items.add(Product( "Laptop",
"Laptop é a
ferramenta de desenvolvimento mais produtiva", 2000,

"laptop.png", 0));

items.add(Product( "Tablet",
"Tablet é o
dispositivo mais útil para reuniões", 1500, "tablet.png", 0));

items.add(Product( "Pendrive",
"Pendrive é um
meio de armazenamento útil", 100, "pendrive.png",
0));

itens.add(Produto(

61
Machine Translated by Google

Vibração

"Unidade de disquete",
"Unidade de disquete é um meio de armazenamento de resgate útil", 20,

"floppy.png", 0));

devolver itens;
}

importar produto.dart em main.dart

importar 'Produto.dart';

• Vamos mudar nosso novo widget, RatingBox, para suportar o conceito scoped_model.

class RatingBox estende StatelessWidget { RatingBox({Key key,


this.item}): super(key: key);

item final do produto;

Construção de widget (contexto BuildContext) {


duplo _tamanho = 20;
imprimir(item.classificação);

return
Row( mainAxisAlignment: MainAxisAlignment.end, crossAxisAlignment:
CrossAxisAlignment.end, mainAxisSize: MainAxisSize.max, filhos:
<Widget>[ Container( preenchimento: EdgeInsets.all(0),
filho: IconButton( ícone:
(item.rating >= 1?
Ícone( Icons.star, tamanho: _size,

)
:
Icon( Icons.star_border, size:
_size, )), color:

Colors.red[500], onPressed: () =>


this.item.updateRating(1), iconSize: _size, ), ),
Container( preenchimento:

EdgeInsets.all(0),
filho: IconButton( ícone: (item.rating >=
2 ? Icon( Icons.star,
tamanho: _size,

)
: Ícone
( Icons.star_border,
tamanho: _size,

62
Machine Translated by Google

Vibração

)),
cor: Colors.red[500], onPressed: () =>
this.item.updateRating(2), iconSize: _size, ), ), Container( preenchimento:
EdgeInsets.all(0), filho:

IconButton( ícone:
(item.rating >= 3 ? Ícone( Icons.star, tamanho:
_size,

)
:
Icon( Icons.star_border,
size: _size, )),

color: Colors.red[500],
onPressed: () => this.item.updateRating(3), iconSize:
_size, ), ), ], );

}
}

Aqui, estendemos o RatingBox de StatelessWidget em vez de StatefulWidget.


Além disso, usamos o método updateRating do modelo Product para definir a classificação.

• Vamos modificar nosso widget ProductBox para funcionar com Product, ScopedModel e
Classe ScopedModelDescendant.

classe ProductBox estende StatelessWidget {


ProductBox({chave-chave, this.item}): super(chave: chave);

item final do produto;

Construção de widget (contexto BuildContext)


{ return
Container( preenchimento:
EdgeInsets.all(2),
altura: 140,
filho: Cartão( filho: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly, filhos:
<Widget>[ Image.asset("assets/
appimages/" + this.item.image), Expanded( child: Container( padding:

EdgeInsets.all(5), child:
ScopedModel<Product >( modelo:
este.item, filho: Coluna (

63
Machine Translated by Google

Vibração

mainAxisAlignment:
MainAxisAlignment.spaceEvenly, filhos:
<Widget>[
Text(este.item.nome,
estilo:
TextStyle(fontWeight:
Intensidade da fonte: Negrito)),
Text(este.item.descrição), Text("Preço:
" +
este.item.preço.toString()),
ScopedModelDescendant<Produto>(
construtor: (contexto, filho, item) {
return RatingBox(item: item); }) ], ))))

]),
));
}
}

Aqui, agrupamos o widget RatingBox em ScopedModel e ScopedModelDecendant.

• Altere o widget MyHomePage para usar nosso widget ProductBox.

class MyHomePage estende StatelessWidget


{ MyHomePage({Key key, this.title}): super(key: key);

título final da String;

itens finais = Product.getProducts();

@override
Widget build(BuildContext context) { return
Scaffold( appBar:
AppBar(title: Text("Navegação do Produto")), body: ListView.builder(

itemCount: itens.length,
itemBuilder: (contexto, índice) { return
ProductBox(item: itens[índice]); }, ));

}
}

Aqui, usamos ListView.builder para construir dinamicamente nossa lista de produtos.

• O código completo da aplicação é o seguinte:

Produto.dart

importar 'pacote:scoped_model/scoped_model.dart';

classe Produto estende Modelo {

64
Machine Translated by Google

Vibração

nome da string final;


descrição final da String; preço
interno final; imagem
final da String; classificação
interna;

Produto(este.nome, esta.descrição, este.preço, esta.imagem, esta.classificação);

fábrica Product.fromMap(Map<String, dynamic> json) { return


Product( json['nome'],
json['descrição'],
json['preço'], json['imagem'],
json['classificação' ], );n

nulo cn
"Laptop é a ferramenta de desenvolvimento mais produtiva",
2000,
"laptop.png", 0));

items.add(Product( "Tablet"cnvn, "Tablet é o dispositivo mais útil para reuniões",


1500,
"tablet.png", 0));

items.add(Product( "Pendrive",
"Pendrive é um
meio de armazenamento útil", 100, "pendrive.png",
0));

items.add(Product( "Floppy
Drive", "Floppy Drive
é um meio de armazenamento de resgate útil", 20, "floppy.png", 0));

devolver itens;
}
}
principal.dart

importar 'pacote:flutter/material.dart'; importar


'pacote:scoped_model/scoped_model.dart'; importar 'Produto.dart';

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

class MyApp extends StatelessWidget { // Este widget


é a raiz do seu aplicativo.

65
Machine Translated by Google

Vibração

@sobrepor
Construção de widget (contexto BuildContext) {
return MaterialApp (título:
'Flutter Demo', tema: ThemeData
(primarySwatch:
Colors.blue, ), home: MyHomePage

(título: 'Página inicial de demonstração do estado do produto'), );

}
}

class MyHomePage estende StatelessWidget {


MyHomePage({chave-chave, this.title}): super(chave: chave);

título final da String;

itens finais = Product.getProducts();

@override
Widget build(BuildContext context) { return
Scaffold( appBar:
AppBar(title: Text("Navegação do Produto")), body: ListView.builder(

itemCount: itens.length, itemBuilder:


(contexto, índice) { return ProductBox(item:
itens[índice]); }, ));

}
}

class RatingBox estende StatelessWidget {


RatingBox({Chave chave, this.item}): super(chave: chave);

item final do produto;

Construção de widget (contexto BuildContext) {


duplo _tamanho = 20;
imprimir(item.classificação);

return
Row( mainAxisAlignment: MainAxisAlignment.end, crossAxisAlignment:
CrossAxisAlignment.end, mainAxisSize: MainAxisSize.max, filhos:
<Widget>[ Container( preenchimento: EdgeInsets.all(0),
filho: IconButton( ícone:
(item.rating >= 1?
Ícone( Icons.star, tamanho: _size,

)
: Ícone (

66
Machine Translated by Google

Vibração

Icons.star_border,
tamanho:

_size, )), cor: Colors.red[500],


onPressed: () => this.item.updateRating(1), iconSize: _size, ), ),
Container( preenchimento:

EdgeInsets.all
(0), filho: IconButton( ícone: (item.rating
>= 2 ? Icon( Icons.star,
tamanho: _size,

)
:
Icon( Icons.star_border, size:
_size, )), color:

Colors.red[500], onPressed: ()
=> this.item.updateRating(2), iconSize: _size, ), ),
Container( preenchimento:

EdgeInsets.all(0), filho: IconButton( ícone:


(item.rating >= 3 ?
Icon( Icons.star, tamanho: _size,

)
:
Icon( Icons.star_border, size:
_size, )), color:

Colors.red[500], onPressed: ()
=> this.item.updateRating(3), iconSize: _size, ), ), ], );

}
}

classe ProductBox estende StatelessWidget {


ProductBox({chave-chave, this.item}): super(chave: chave);

item final do produto;

Construção de widget (contexto BuildContext)


{ return Container
(preenchimento: EdgeInsets.all (2),

67
Machine Translated by Google

Vibração

altura: 140,
filho: Cartão
(filho: Linha (
mainAxisAlignment: MainAxisAlignment.spaceEvenly, filhos:
<Widget>[ Image.asset("assets/
appimages/" + this.item.image), Expanded( child: Container( padding:

EdgeInsets.all(5), child:
ScopedModel<Product >(modelo:
this.item, filho:

Column( mainAxisAlignment:
MainAxisAlignment.spaceEvenly, filhos:
<Widget>[
Text(este.item.nome, estilo:

TextStyle(fontWeight:
Intensidade da fonte: Negrito)),
Text(este.item.descrição), Text("Preço:
" +
este.item.preço.toString()),
ScopedModelDescendant<Produto>(
construtor: (contexto, filho, item) {
return RatingBox(item: item); }) ], ))))

]),
));
}
}

Por fim, compile e execute o aplicativo para ver seu resultado. Funcionará de forma semelhante ao exemplo
anterior, exceto que o aplicativo usa o conceito scoped_model.

Navegação e roteamento
Em qualquer aplicação, navegar de uma página/tela para outra define o fluxo de trabalho da aplicação. A forma
como a navegação de uma aplicação é tratada é chamada de Roteamento.
Flutter fornece uma classe de roteamento básica – MaterialPageRoute e dois métodos – Navigator.push e
Navigator.pop, para definir o fluxo de trabalho de uma aplicação.

MaterialPageRoute
MaterialPageRoute é um widget usado para renderizar sua UI, substituindo a tela inteira por uma animação
específica da plataforma.

MaterialPageRoute(construtor: (contexto) => Widget())

Aqui, o construtor aceitará uma função para construir seu conteúdo, suprindo o contexto atual do aplicativo.

Navegação.push

68
Machine Translated by Google

Vibração

Navigation.push é usado para navegar para uma nova tela usando o widget MaterialPageRoute.

Navigator.push(contexto,

MaterialPageRoute(construtor: (contexto) => Widget()),


);

Navegação.pop
Navigation.pop é usado para navegar para a tela anterior.

Navigator.push(contexto);

Vamos criar um novo aplicativo para entender melhor o conceito de navegação.

Crie um novo aplicativo Flutter no Android Studio, product_nav_app

• Copie a pasta de ativos de product_nav_app para product_state_app e adicione ativos


dentro do arquivo pubspec.yaml

vibração:

ativos:
- assets/appimages/floppy.png - assets/
appimages/iphone.png - assets/appimages/
laptop.png - assets/appimages/
pendrive.png - assets/appimages/pixel.png -
assets/appimages/tablet.png

• Substitua o código de inicialização padrão (main.dart) pelo nosso código de inicialização.

importar 'pacote:flutter/material.dart';

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

class MyApp extends StatelessWidget { // Este widget


é a raiz do seu aplicativo. @override Compilação do widget (contexto
BuildContext)
{
return MaterialApp (título:
'Flutter Demo', tema: ThemeData
(primarySwatch:
Colors.blue, ), home: MyHomePage

(título: 'Página inicial de demonstração do estado do produto'), );

}
}

class MyHomePage estende StatelessWidget


{ MyHomePage({Key key, this.title}): super(key: key);

título final da String;

69
Machine Translated by Google

Vibração

@override
Widget build (contexto BuildContext) { return Scaffold( appBar:
AppBar( title:
Text(this.title), ), body:
Center( child: Text( 'Hello World', )),

);
}
}

• Vamos criar uma classe Produto para organizar as informações do produto.

classe Produto { final


String nome; descrição
final da String; preço interno final;
imagem final da String;

Produto(este.nome, esta.descrição, este.preço, esta.imagem);


}

• Vamos escrever um método getProducts na classe Product para gerar nosso modelo
registros do produto.

static List<Produto> getProdutos() {


List<Produto> itens = <Produto>[];

items.add(Product( "Pixel",
"Pixel é o
telefone com mais recursos de todos os tempos", 800,

"pixel.png"));

items.add(Product( "Laptop",
"Laptop é a
ferramenta de desenvolvimento mais produtiva", 2000,

"laptop.png"));

items.add(Product( "Tablet",
"Tablet é o
dispositivo mais útil para reuniões", 1500, "tablet.png"));

items.add(Product( "Pendrive",
"Pendrive é um
meio de armazenamento útil",

70
Machine Translated by Google

Vibração

100,
"pendrive.png"));

items.add(Product( "Floppy
Drive", "Floppy Drive
é um meio de armazenamento de resgate útil", 20, "floppy.png"));

devolver itens;
}

importar produto.dart em main.dart

importar 'Produto.dart';

• Vamos incluir nosso novo widget, RatingBox

class RatingBox estende StatefulWidget { @override

_RatingBoxState createState() => _RatingBoxState();


}

classe _RatingBoxState estende State<RatingBox> {


int _classificação = 0;

void _setRatingAsOne() { setState(()


{ _rating = 1; });

void _setRatingAsTwo() { setState(()


{ _rating = 2; });

void _setRatingAsThree() {
setState(()
{ _classificação
= 3; });
}

Construção de widget (contexto BuildContext) {


duplo _tamanho = 20;
imprimir(_classificação);

return
Row( mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.end, mainAxisSize:
MainAxisSize.max, filhos:

<Widget>[ Container( preenchimento:


EdgeInsets.all(0), filho: IconButton(

71
Machine Translated by Google

Vibração

ícone: (_rating >= 1 ? Ícone

(Ícones.estrela, tamanho:
_tamanho,
)
:
Icon( Icons.star_border, tamanho:
_size, )), cor:

Colors.red[500], onPressed:
_setRatingAsOne, iconSize: _size, ), ),
Container( preenchimento:

EdgeInsets.all(0),
filho: IconButton(

ícone: (_rating >= 2 ? Ícone

(Ícones.estrela, tamanho:
_tamanho,
)
: Ícone
( Icons.star_border,
tamanho: _size, )),
cor:
Colors.red [500], onPressed:
_setRatingAsTwo, iconSize: _size, ), ),
Container ( preenchimento:

EdgeInsets.all
(0), filho: IconButton (

ícone: (_rating >= 3 ? Ícone

(Ícones.estrela, tamanho:
_tamanho,
)
:
Icon( Icons.star_border, size:
_size, )), color:

Colors.red[500], onPressed:
_setRatingAsThree, iconSize: _size, ), ), ], );

}
}

72
Machine Translated by Google

Vibração

• Vamos modificar nosso widget ProductBox para funcionar com nossa nova classe Product.

class ProductBox estende StatelessWidget


{ ProductBox({Key key, this.item}):
super(key: key);

item final do Produto;

Construção de widget (contexto BuildContext)


{ return
Container( preenchimento:
EdgeInsets.all(2),
altura: 140,
filho: Cartão( filho: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly, filhos:

<Widget>[ Image.asset("assets/appimages/" + this.item.image),

Expanded( child:
Container( padding: EdgeInsets.all(5),
child:

Column( mainAxisAlignment : MainAxisAlignment.spaceEvenly,


filhos: <Widget>[
Text(este.item.nome,
estilo: TextStyle(fontWeight:
Intensidade da fonte: Negrito)),
Text(this.item.description),
Text("Preço: " + this.item.price.toString()), RatingBox(), ], )))

]),
));
}
}

• Vamos reescrever nosso widget MyHomePage para funcionar com o modelo Product e listar todos os
produtos usando ListView.

class MyHomePage estende StatelessWidget {


MyHomePage({chave-chave, this.title}): super(chave: chave);

título final da String;

itens finais = Product.getProducts();

@override
Widget build(BuildContext context) { return
Scaffold( appBar:
AppBar(title: Text("Navegação do Produto")), body: ListView.builder(

itemCount: itens.length,
itemBuilder: (contexto, índice) {

73
Machine Translated by Google

Vibração

return GestureDetector( filho:


ProductBox(item: itens[índice]), onTap: ()

{ Navigator.push( context,

MaterialPageRoute(
construtor: (contexto) => ProductPage(item:
itens[índice]),

), ); }, ); }, ));
}
}

Aqui, usamos MaterialPageRoute para navegar até a página de detalhes do produto.

• Agora, vamos adicionar ProductPage para mostrar os detalhes do produto.

class ProductPage estende StatelessWidget {


ProductPage({chave-chave, this.item}): super(chave: chave);

item final do produto;

@override
Widget build (contexto BuildContext) { return
Scaffold( appBar:
AppBar( title:
Text(this.item.name), ), body:

Center( child:
Container( padding:
EdgeInsets.all(0),
filho: Coluna
(mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start, filhos:
<Widget>[ Image.asset("assets/
appimages/" +
este.item.imagem),

Expandido( filho:
Container( preenchimento:
EdgeInsets.all(5),
filho: Coluna( mainAxisAlignment:
MainAxisAlignment.spaceEvenly,
filhos: <Widget>[
Text(este.item.nome, estilo:
TextStyle(fontWeight:
Intensidade da fonte: Negrito)),
Text(este.item.descrição), Text("Preço: "
+
este.item.preço.toString()),
RatingBox(),

74
Machine Translated by Google

Vibração

], )))
]),
),

), );
}
}

• O código completo da aplicação é o seguinte:

importar 'pacote:flutter/material.dart';

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

classe Produto { final


String nome; descrição
final da String; preço interno final;
imagem final da String;

Produto(este.nome, esta.descrição, este.preço, esta.imagem);

static List<Produto> getProdutos() {


List<Produto> itens = <Produto>[];

items.add(Product( "Pixel",
"Pixel é o telefone com mais recursos de todos os tempos", 800,
"pixel.png"));

items.add(Product("Laptop", "Laptop é a ferramenta de desenvolvimento mais produtiva",

2000, "laptop.png"));

items.add(Product( "Tablet",
"Tablet é o
dispositivo mais útil para reuniões", 1500, "tablet.png"));

items.add(Product( "Pendrive",
"iPhone é o telefone estilista de todos os tempos", 100, "pendrive.png"));

items.add(Product( "Floppy
Drive", "iPhone é o telefone estilista de todos os tempos", 20, "floppy.png"));

items.add(Product( "iPhone",
"iPhone é o telefone estilista de todos os tempos", 1000, "iphone.png"));

devolver itens;
}
}

75
Machine Translated by Google

Vibração

class MyApp extends StatelessWidget { // Este widget


é a raiz do seu aplicativo. @override Compilação do widget (contexto
BuildContext)
{
return MaterialApp (título:
'Flutter Demo', tema: ThemeData
(primarySwatch:
Colors.blue, ), home: MyHomePage

(título: 'página inicial da demonstração de navegação do produto'), );

}
}

class MyHomePage estende StatelessWidget {


MyHomePage({chave-chave, this.title}): super(chave: chave);

título final da String;

itens finais = Product.getProducts();

@override
Widget build(BuildContext context) { return
Scaffold( appBar:
AppBar(title: Text("Navegação do Produto")), body: ListView.builder(

itemCount: items.length,
itemBuilder: (contexto, índice) { return
GestureDetector( filho:
ProductBox(item: itens[índice]), onTap: ()

{ Navigator.push( context,

MaterialPageRoute(
construtor: (contexto) => ProductPage(item:
itens[índice]),

), ); }, ); }, ));
}
}

class ProductPage estende StatelessWidget {


ProductPage({chave-chave, this.item}): super(chave: chave);

item final do produto;

@sobrepor
Construção de widget (contexto BuildContext)
{ return Scaffold( appBar:
AppBar(

76
Machine Translated by Google

Vibração

título: Texto (this.item.name), ),

corpo: Center
(filho: Container
(preenchimento: EdgeInsets.all (0),
filho: Column
(mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start, filhos:
<Widget
>[ Image.asset("assets/appimages/" + this.item.image),

Expanded( child:
Container( padding: EdgeInsets.all(5),
child:
Column( mainAxisAlignment:
MainAxisAlignment.spaceEvenly,
filhos: <Widget>[
Text(este.item.nome,
estilo: TextStyle(fontWeight:
Intensidade da fonte: Negrito)),
Text(este.item.descrição), Text("Preço:
" +
este.item.preço.toString()),
RatingBox(), ], )))

]),
),

), );
}
}

class RatingBox estende StatefulWidget { @override

_RatingBoxState createState() => _RatingBoxState();


}

classe _RatingBoxState estende State<RatingBox> {


int _classificação = 0;

void _setRatingAsOne()
{ setState(()
{ _rating = 1; });

void _setRatingAsTwo()
{ setState(()
{ _rating = 2; });

void _setRatingAsThree()
{ setState(() {

77
Machine Translated by Google

Vibração

_classificação =
3; });
}

Construção de widget (contexto BuildContext) {


duplo _tamanho = 20;
imprimir(_classificação);

return
Row( mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.end, mainAxisSize:
MainAxisSize.max, filhos:

<Widget>[ Container( preenchimento:


EdgeInsets.all(0), filho: IconButton(
ícone: (_rating >= 1 ? Ícone

(Ícones.estrela, tamanho:
_tamanho,
)
:
Icon( Icons.star_border, tamanho:
_size, )), cor:

Colors.red[500], onPressed:
_setRatingAsOne, iconSize: _size, ), ),
Container( preenchimento:

EdgeInsets.all(0),
filho: IconButton(

ícone: (_rating >= 2 ? Ícone

(Ícones.estrela, tamanho:
_tamanho,
)
: Ícone
( Icons.star_border,
tamanho: _size, )),
cor:
Colors.red [500], onPressed:
_setRatingAsTwo, iconSize: _size, ), ),
Container ( preenchimento:

EdgeInsets.all
(0), filho: IconButton (

ícone: (_rating >= 3 ? Ícone

(Ícones.estrela, tamanho:
_tamanho,
)

78
Machine Translated by Google

Vibração

:
Icon( Icons.star_border,
size: _size, )),

color: Colors.red[500],
onPressed: _setRatingAsThree,
iconSize: _size, ), ), ], );

}
}

classe ProductBox estende StatelessWidget {


ProductBox({chave-chave, this.item}): super(chave: chave);

item final do produto;

Construção de widget (contexto BuildContext)


{ return
Container( preenchimento:
EdgeInsets.all(2),
altura: 140,
filho: Cartão( filho: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly, filhos:

<Widget>[ Image.asset("assets/appimages/" + this.item.image),

Expanded( child:
Container( padding: EdgeInsets.all(5),
child:

Column( mainAxisAlignment :
MainAxisAlignment.spaceEvenly, filhos: <Widget>[
Text(este.item.nome,
estilo: TextStyle(fontWeight:
Intensidade da fonte: Negrito)),
Text(this.item.description),
Text("Preço: " + this.item.price.toString()), RatingBox(), ], )))

]),
));
}
}

79
Machine Translated by Google

Vibração

Execute o aplicativo e clique em qualquer item do produto. Ele mostrará a página de detalhes relevantes. Podemos
ir para a página inicial clicando no botão Voltar. A página da lista de produtos e a página de detalhes do produto
do aplicativo são mostradas a seguir:

80
Machine Translated by Google

Vibração

81
Machine Translated by Google

10. Vibração – Animação Vibração

A animação é um procedimento complexo em qualquer aplicativo móvel. Apesar de sua complexidade, a Animação eleva a
experiência do usuário a um novo nível e proporciona uma rica interação do usuário. Devido à sua riqueza, a animação torna-se
parte integrante dos aplicativos móveis modernos. A estrutura Flutter reconhece a importância da animação e fornece uma

framework simples e intuitivo para desenvolver todos os tipos de animações.

Introdução
Animação é um processo de mostrar uma série de imagens/imagem em uma ordem específica e com uma duração específica
para dar uma ilusão de movimento. Os aspectos mais importantes da animação são os seguintes:

• A animação tem dois valores distintos: valor inicial e valor final. A animação começa no valor inicial e passa por uma série de
valores intermediários e finalmente termina nos valores finais . Por exemplo, para animar o desaparecimento de um widget,
o valor inicial será a opacidade total e o valor final será a opacidade zero.

• Os valores intermediários podem ser de natureza linear ou não linear (curva) e podem ser configurados. Entenda que a
animação funciona conforme está configurada. Cada configuração fornece uma sensação diferente à animação. Por
exemplo, o desbotamento de um widget será de natureza linear, enquanto o salto de uma bola será de natureza não linear.

• A duração do processo de animação afeta a velocidade (lentidão ou rapidez) do


animação.

• A capacidade de controlar o processo de animação, como iniciar a animação, parar a animação, repetir a animação para definir
um número de vezes, reverter o processo de animação, etc.,

• No Flutter, o sistema de animação não faz nenhuma animação real. Em vez disso, fornece apenas os valores necessários
em cada quadro para renderizar as imagens.

Aulas baseadas em animação


O sistema de animação Flutter é baseado em objetos de animação. As principais classes de animação e seu uso são as
seguintes:

Animação

Gera valores interpolados entre dois números durante um determinado período. As aulas de animação mais comuns são:

• Animação<double> - interpola valores entre dois números decimais

• Animation<Color> - interpola cores entre duas cores

• Animation<Size> - interpola tamanhos entre dois tamanhos

82
Machine Translated by Google

Vibração

• AnimationController - Objeto de animação especial para controlar a própria animação. Ele gera novos valores sempre
que a aplicação está pronta para um novo quadro. Ele suporta animação linear e o valor começa de 0,0 a 1,0.

controlador = AnimationController(duração: const Duração(segundos: 2), vsync: this);

Aqui, o controlador controla a animação e a opção de duração controla a duração do processo de animação. vsync
é uma opção especial utilizada para otimizar o recurso utilizado na animação.

Animação Curva

Semelhante ao AnimationController, mas oferece suporte a animação não linear. CurvedAnimation pode ser usado junto com
o objeto Animation conforme abaixo:

controlador = AnimationController(duração: const Duração(segundos: 2), vsync: this);

animação = CurvedAnimation(pai: controlador, curva: Curves.easeIn)

Interpolação<T>

Derivado de Animatable<T> e usado para gerar números entre quaisquer dois números diferentes de 0 e 1. Ele pode ser
usado junto com o objeto Animation usando o método animate e passando o objeto Animation real.

Controlador AnimationController = AnimationController(


duração: const Duração (milissegundos: 1000), vsync: this);
Animação<int> customTween = IntTween(início: 0, fim: 255).animate(controlador);

Tween também pode ser usado junto com CurvedAnimation conforme abaixo:

Controlador AnimationController = AnimationController(duração: const Duration(milissegundos: 500),


vsync: this);
curva de animação final = CurvedAnimation (pai: controlador, curva: Curves.easeOut);

Animação<int> customTween = IntTween(início: 0, fim: 255).animate(curva);

Aqui, controller é o controlador de animação real. curve fornece o tipo de não linearidade e o customTween fornece intervalo
personalizado de 0 a 255.

Fluxo de trabalho do FlutterAnimation


O fluxo de trabalho da animação é o seguinte:

• Defina e inicie o controlador de animação no initState do StatefulWidget.

AnimationController(duração: const Duração(segundos: 2), vsync: this); animação = Tween<double>(início:


0, fim: 300).animate(controlador);
controlador.forward();

• Adicionar ouvinte baseado em animação, addListener para alterar o estado do widget

83
Machine Translated by Google

Vibração

animação = Tween<double>(begin: 0, end: 300).animate(controller) ..addListener(() { setState(() { //


O estado que mudou aqui
é o do objeto de
animação
valor. });

});

• Widgets integrados, AnimatedWidget e AnimatedBuilder podem ser usados para pular esse processo. Ambos os widgets
aceitam o objeto Animation e obtêm os valores atuais necessários para a animação.

• Obtenha os valores da animação durante o processo de construção do widget e depois aplique-os para largura, altura
ou qualquer propriedade relevante em vez do valor original.

filho: Container (altura:


animação.valor, largura:
animação.valor, filho: <Widget>,

Aplicativo de trabalho
Vamos escrever um aplicativo simples baseado em animação para entender o conceito de animação no framework Flutter.

• Crie um novo aplicativo Flutter no Android Studio, product_animation_app

• Copie a pasta de ativos de product_nav_app para product_animation_app e adicione ativos dentro do arquivo
pubspec.yaml

vibração:

ativos:
- assets/appimages/floppy.png
- ativos/appimages/iphone.png
- ativos/appimages/laptop.png
- assets/appimages/pendrive.png
- ativos/appimages/pixel.png
- ativos/appimages/tablet.png

• Remova o código de inicialização padrão (main.dart).

• Adicionar importação e função principal básica

importar 'pacote:flutter/material.dart';

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

• Crie o widget MyApp derivado de StatefulWidgtet

classe MyApp estende StatefulWidget {


_MyAppState createState() => _MyAppState();
}

84
Machine Translated by Google

Vibração

• Crie o widget _MyAppState e implemente initState e descarte além do método de construção padrão.

class _MyAppState estende State<MyApp> com SingleTickerProviderStateMixin {

Animação<duplo> animação;
Controlador AnimationController;

@override
void initState() {
super.initState(); controlador
= AnimationController(duração: const Duração(segundos: 10), vsync: this);

animação = Tween<double>(início: 0,0, fim: 1,0).animate(controlador); controlador.forward();

// Este widget é a raiz da sua aplicação. @override Widget build


(contexto
BuildContext) { controller.forward(); return
MaterialApp( título: 'Flutter
Demo', tema:
ThemeData( primárioSwatch:
Colors.blue, ), home:
MyHomePage( título: 'Página inicial de

demonstração de layout
de produto', animação: animação,)
);
}

@override
void dispor()
{ controller.dispose();
super.dispose();
}
}

Aqui,

• No método initState, criamos um objeto controlador de animação (controller), um objeto de animação (animação) e
iniciamos a animação usando controller.forward.

• No método descartar, descartamos o objeto controlador de animação (controlador).

• No método build, envie animação para o widget MyHomePage por meio do construtor. Agora, o widget MyHomePage
pode usar o objeto de animação para animar seu conteúdo.

• Agora, adicione o widget ProductBox

class ProductBox estende StatelessWidget { ProductBox({chave-


chave, este.nome, esta.descrição, este.preço, esta.imagem})

85
Machine Translated by Google

Vibração

: super(chave: chave);

nome da string final;


descrição final da String; preço
interno final; imagem
final da String;

Construção de widget (contexto BuildContext)


{ return
Container( preenchimento:
EdgeInsets.all(2),
altura: 140,
filho: Cartão( filho: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly, filhos:
<Widget>[ Image.asset("assets/
appimages/" + image), Expanded( child:

Container( padding:
EdgeInsets.all(5), child:

Column( mainAxisAlignment: MainAxisAlignment.spaceEvenly , filhos:


<Widget>[ Text(this.name,
style:
TextStyle(fontWeight:
Intensidade da fonte: Negrito)),
Text(this.description),
Text("Preço: " + this.price.toString()), ], )))

])));
}
}

• Crie um novo widget, MyAnimatedWidget, para fazer uma animação simples de fade usando opacidade.

class MyAnimatedWidget estende StatelessWidget


{ MyAnimatedWidget({this.child, this.animation});

filho do Widget final;


animação final<double> animação;

Construção do widget (contexto BuildContext) => Center( filho:


AnimatedBuilder(
animação: animação,
construtor: (contexto, filho) => Container( filho:
Opacidade (opacidade: animação.valor, filho: filho), ), filho: filho),

);
}

• Aqui, usamos AniatedBuilder para fazer nossa animação. AnimatedBuilder é um widget que constrói seu
conteúdo enquanto faz a animação ao mesmo tempo. Aceita um objeto de animação para obter o valor
atual da animação. Usamos animação

86
Machine Translated by Google

Vibração

value, Animation.value para definir a opacidade do widget filho. Na verdade, o widget irá animar o widget
filho usando o conceito de opacidade.

• Por fim, crie o widget MyHomePage e use o objeto de animação para animar qualquer conteúdo.

class MyHomePage estende StatelessWidget {


MyHomePage({chave-chave, this.title, this.animation}): super(key: key);

título final da String;


animação final<double> animação;

@override
Widget build (contexto BuildContext) { return
Scaffold( appBar:
AppBar(title: Text("Listagem de produtos")), body:
ListView( ShrinkWrap:
true, padding: const
EdgeInsets.fromLTRB(2.0, 10.0, 2.0, 10.0) , filhos: <Widget>[ FadeTransition(child:
ProductBox( nome:
"iPhone", descrição: "iPhone é o telefone
estilista de todos os
tempos", preço: 1000, imagem: "iphone.png"), opacidade:
animação),
MyAnimatedWidget( filho:
ProductBox (nome: "Pixel",
descrição: "Pixel é o telefone com mais recursos
de todos os
tempos", preço: 800, imagem: "pixel.png"),

animação: animação),

ProductBox( nome:
"Laptop", descrição: "Laptop é a ferramenta de desenvolvimento mais produtiva",
preço: 2000,
imagem: "laptop.png"),

ProductBox( nome:
"Tablet", descrição: "Tablet é o dispositivo mais útil de todos os tempos
reunião",
preço: 1500,
imagem: "tablet.png"),

ProductBox( nome:
"Pendrive", descrição: "Pendrive é um meio de armazenamento útil",
preço: 100,
imagem: "pendrive.png"),

ProductBox( nome: "Disquete


Drive", description: "A unidade de disquete é um armazenamento de resgate útil
médio",
preço: 20,
imagem: "floppy.png"),
],

87
Machine Translated by Google

Vibração

));
}
}

Aqui, usamos FadeAnimation e MyAnimationWidget para animar os dois primeiros itens da lista. FadeAnimation
é uma classe de animação integrada, que usamos para animar seu filho usando o conceito de opacidade.

• O código completo é o seguinte:

importar 'pacote:flutter/material.dart';

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

classe MyApp estende StatefulWidget {


_MyAppState createState() => _MyAppState();
}

class _MyAppState estende State<MyApp> com SingleTickerProviderStateMixin {

Animação<duplo> animação;
Controlador AnimationController;

@override
void initState() {
super.initState();
controlador = AnimationController(duração: const Duração(segundos: 10), vsync: this);
animação =
Tween<double>(início: 0,0, fim: 1,0).animate(controlador); controlador.forward();

// Este widget é a raiz da sua aplicação. @override Widget build


(contexto
BuildContext) { controller.forward(); return
MaterialApp( título: 'Flutter
Demo', tema:
ThemeData( primárioSwatch:
Colors.blue, ), home:
MyHomePage( título: 'Página inicial

de demonstração de
layout de produto', animação: animação,)
);
}

@override
void dispor()
{ controller.dispose();
super.dispose();
}
}

class MyHomePage estende StatelessWidget {


MyHomePage({chave-chave, this.title, this.animation}): super(key: key);

88
Machine Translated by Google

Vibração

título final da String;


animação final<double> animação;

@override
Widget build (contexto BuildContext) { return
Scaffold( appBar:
AppBar(title: Text("Listagem de produtos")), body:
ListView( ShrinkWrap:
true, padding: const
EdgeInsets.fromLTRB(2.0, 10.0, 2.0, 10.0) , filhos: <Widget>[ FadeTransition(child:
ProductBox( nome:
"iPhone", descrição: "iPhone é o telefone
estilista de todos os
tempos", preço: 1000, imagem: "iphone.png"), opacidade:
animação),
MyAnimatedWidget( filho:
ProductBox (nome: "Pixel",
descrição: "Pixel é o telefone com mais recursos
de todos os
tempos", preço: 800, imagem: "pixel.png"),

animação: animação),

ProductBox( nome:
"Laptop", descrição: "Laptop é a ferramenta de desenvolvimento mais produtiva",
preço: 2000,
imagem: "laptop.png"),

ProductBox( nome:
"Tablet", descrição: "Tablet é o dispositivo mais útil de todos os tempos
reunião",
preço: 1500,
imagem: "tablet.png"),

ProductBox( nome:
"Pendrive", descrição: "Pendrive é um meio de armazenamento útil",
preço: 100,
imagem: "pendrive.png"),
ProductBox(
name: "Unidade de disquete",
description: "A unidade de disquete é um armazenamento de resgate útil
médio",
preço: 20,
imagem: "floppy.png"),

], ));
}
}

classe ProductBox estende StatelessWidget {


ProductBox({chave-chave, este.nome, esta.descrição, este.preço, esta.imagem}):
super(chave:
chave);

89
Machine Translated by Google

Vibração

nome da string final;


descrição final da String; preço
interno final; imagem
final da String;

Construção de widget (contexto BuildContext)


{ return
Container( preenchimento:
EdgeInsets.all(2),
altura: 140,
filho: Cartão( filho: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly, filhos:
<Widget>[ Image.asset("assets/
appimages/" + image), Expanded( child:

Container( padding:
EdgeInsets.all(5), child:

Column( mainAxisAlignment: MainAxisAlignment.spaceEvenly , filhos:


<Widget>[ Text(this.name,
style:
TextStyle(fontWeight:
Intensidade da fonte: Negrito)),
Text(this.description),
Text("Preço: " + this.price.toString()), ], )))

])));
}
}

class MyAnimatedWidget estende StatelessWidget


{ MyAnimatedWidget({this.child, this.animation});

filho do Widget final;


animação final<double> animação;

Construção do widget (contexto BuildContext) => Center( filho:


AnimatedBuilder(
animação: animação,
construtor: (contexto, filho) => Container( filho:
Opacidade (opacidade: animação.valor, filho: filho), ), filho: filho),

);
}

90
Machine Translated by Google

Vibração

• Compile e execute o aplicativo para ver os resultados. A versão inicial e final do


a aplicação é a seguinte:

91
Machine Translated by Google

Vibração

92
Machine Translated by Google

Vibração
11. Flutter – Escrevendo código específico do Android

Flutter fornece uma estrutura geral para acessar recursos específicos da plataforma. Isso permite que o desenvolvedor
estenda a funcionalidade da estrutura Flutter usando código específico da plataforma.
Funcionalidades específicas da plataforma, como câmera, nível de bateria, navegador, etc., podem ser acessadas
facilmente por meio da estrutura.

A ideia geral de acessar o código específico da plataforma é através de um protocolo de mensagens simples. O código
Flutter, o Cliente e o código da plataforma e o Host são vinculados a um canal de mensagem comum. O cliente envia
mensagem ao Host através do Canal de Mensagens. O Host escuta no Canal de Mensagens, recebe a mensagem e
faz as funcionalidades necessárias e por fim, retorna o resultado ao Cliente através do Canal de Mensagens.

A arquitetura de código específica da plataforma é mostrada no diagrama de blocos abaixo:

O protocolo de mensagens usa um codec de mensagem padrão (classe StandardMessageCodec) que suporta
serialização binária de valores semelhantes a JSON, como números, strings, booleanos, etc.. A serialização e
desserialização funcionam de forma transparente entre o cliente e o
hospedar.

Vamos escrever um aplicativo simples para abrir um navegador usando Android SDK e entender como invocar o SDK
a partir de um aplicativo flutter.

• Crie um novo aplicativo Flutter no Android Studio, flutter_browser_app

• Substitua o código main.dart pelo código abaixo:

importar 'pacote:flutter/material.dart';

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

class MyApp estende StatelessWidget {


@sobrepor
Construção de widget (contexto BuildContext) {
retornarMaterialApp(
título: 'Demonstração de Flutter',
tema: ThemeData(
primárioSwatch: Colors.blue,
),
home: MyHomePage (título: 'Página inicial de demonstração do Flutter'),

93
Machine Translated by Google

Vibração

);
}
}

class MyHomePage estende StatelessWidget {


MyHomePage({chave-chave, this.title}): super(chave: chave);

título final da String;

@override
Widget build (contexto BuildContext) { return
Scaffold( appBar:
AppBar( title:
Text(this.title), ), body: Center( child:

RaisedButton( child:
Text('Open Browser'),
onPressed: null, ) , ), );

}
}

• Aqui, criamos um novo botão para abrir o navegador e definimos seu método onPressed como nulo.

• Agora, importe os seguintes pacotes:

importar 'dardo: assíncrono';


importar 'pacote:flutter/services.dart';

• Aqui, services.dart inclui a funcionalidade para invocar código específico da plataforma.

• Crie um novo canal de mensagens no widget MyHomePage.

plataforma const estática = const


MethodChannel('flutterapp.tutorialspoint.com/browser');

• Escreva um método, _openBrowser para invocar o método específico da plataforma, o método


openBrowser através do canal de mensagens.

Future<void> _openBrowser() async { try { final int


result
= await platform.invokeMethod('openBrowser',
<String, String>{ 'url':
"https://flutter.dev" });

} em PlatformException captura (e) {


// Não é possível abrir o navegador print(e);

}
}

94
Machine Translated by Google

Vibração

Aqui, usamos platform.invokeMethod para invocar o openBrowser (explicado nas próximas etapas). openBrowser
tem um argumento url para abrir uma url específica.

• Altere o valor da propriedade onPressed do RaisedButton de null para _openBrowser.

onPressed: _openBrowser,

• Abra MainActivity.java (dentro da pasta android) e importe a biblioteca necessária:

importar android.app.Activity; importar


android.content.Intent; importar
android.net.Uri; importar
android.os.Bundle;

importar io.flutter.app.FlutterActivity; importar


io.flutter.plugin.common.MethodCall; importar
io.flutter.plugin.common.MethodChannel; importar
io.flutter.plugin.common.MethodChannel.MethodCallHandler; importar
io.flutter.plugin.common.MethodChannel.Result; importar
io.flutter.plugins.GeneratedPluginRegistrant;

• Escreva um método, openBrowser para abrir um navegador

private void openBrowser (MethodCall call, Result result, String url) { Activity Activity = this; if (activity
== null)

{ result.error("ACTIVITY_NOT_AVAILABLE", "O navegador não pode ser aberto


sem atividade em primeiro plano", null); return;

Intenção intenção = nova Intent(Intent.ACTION_VIEW);


intent.setData(Uri.parse(url));

atividade.startActivity(intenção);
resultado.sucesso((Objeto) verdadeiro);
}

• Agora, defina o nome do canal na classe MainActivity:

private static final String CHANNEL =


"flutterapp.tutorialspoint.com/browser";

• Escreva o código específico do Android para definir o tratamento de mensagens no método onCreate.

new MethodChannel(getFlutterView(), CHANNEL).setMethodCallHandler( new


MethodCallHandler() { @Override
public void
onMethodCall(MethodCall call, Result result) {

String url = call.argument("url");

if (call.method.equals("openBrowser")) {

95
Machine Translated by Google

Vibração

openBrowser(chamada, resultado, url); }


else
{ resultado.notImplemented();
}

}
});

Aqui, criamos um canal de mensagem usando a classe MethodChannel e usamos a classe MethodCallHandler
para lidar com a mensagem. onMethodCall é o método real responsável por chamar o código específico da
plataforma correta verificando a mensagem. O método onMethodCall extrai o URL da mensagem e então
invoca o openBrowser somente quando a chamada do método é openBrowser. Caso contrário, ele retornará o
método notImplemented.

O código fonte completo do aplicativo é o seguinte:

principal.dart

MainActivity.java

pacote com.tutorialspoint.flutterapp.flutter_browser_app;

importar android.app.Activity; importar


android.content.Intent; importar
android.net.Uri; importar
android.os.Bundle;

importar io.flutter.app.FlutterActivity; importar


io.flutter.plugin.common.MethodCall; importar
io.flutter.plugin.common.MethodChannel.Result; importar
io.flutter.plugins.GeneratedPluginRegistrant;

classe pública MainActivity estende FlutterActivity { private static


final String CHANNEL = "flutterapp.tutorialspoint.com/
browser";

@Override
protegido void onCreate(Bundle saveInstanceState) {
super.onCreate(savedInstanceState);
GeneratedPluginRegistrant.registerWith(this);

new MethodChannel(getFlutterView(), CHANNEL).setMethodCallHandler( new


MethodCallHandler() { @Override
public void
onMethodCall(MethodCall call, Result result) {

String url = call.argument("url");

if (call.method.equals("openBrowser"))
{ openBrowser(chamada, resultado, url); }
else
{ resultado.notImplemented();
}

96
Machine Translated by Google

Vibração

});
}

private void openBrowser(MethodCall call, Resultado resultado, String url) {


Atividade atividade = isto; if (activity
== null)
{ result.error("ACTIVITY_NOT_AVAILABLE", "O navegador não pode ser aberto
sem atividade em primeiro plano", null); return;

Intenção intenção = nova Intent(Intent.ACTION_VIEW);


intent.setData(Uri.parse(url));

atividade.startActivity(intenção);
resultado.sucesso((Objeto) verdadeiro);
}
}

principal.dart

importar 'pacote:flutter/material.dart';

importar 'dardo: assíncrono';


importar 'pacote:flutter/services.dart';

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

class MyApp estende StatelessWidget { @override

Construção de widget (contexto BuildContext) {


return MaterialApp(título:
'Flutter Demo', tema:
ThemeData(primárioSwatch:
Colors.blue, ), home:

MyHomePage(título: 'Página inicial da demonstração Flutter'), );

}
}

class MyHomePage estende StatelessWidget {


MyHomePage({chave-chave, this.title}): super(chave: chave);

título final da String;

plataforma const estática = const


MethodChannel('flutterapp.tutorialspoint.com/browser'); Futuro<void>
_openBrowser() assíncrono {
tente
{ final int resultado = aguarde platform.invokeMethod('openBrowser',
<String, String>{ 'url':
"https://flutter.dev" });

97
Machine Translated by Google

Vibração

} em PlatformException captura (e) {


// Não é possível abrir o navegador
print(e);
}
}

@override
Widget build (contexto BuildContext) { return
Scaffold( appBar:
AppBar( title:
Text(this.title), ), body:

Center( child:
RaisedButton( child:
Text('Open Browser'), onPressed:
_openBrowser, ) , ), );

}
}

Execute o aplicativo e clique no botão Abrir navegador e você verá que o navegador foi iniciado. O aplicativo
Navegador - página inicial é mostrado na captura de tela aqui:

98
Machine Translated by Google

Vibração

99
Machine Translated by Google

Vibração
12. Flutter – Escrevendo código específico para iOS

O acesso ao código específico do iOS é semelhante ao da plataforma Android, exceto que usa linguagens
específicas do iOS - Objective-C ou Swift e iOS SDK. Caso contrário, o conceito é o mesmo da plataforma
Android.

Vamos escrever o mesmo aplicativo do capítulo anterior também para a plataforma iOS.
• Vamos criar um novo aplicativo no Android Studio (macOS), flutter_browser_ios_app

• Siga as etapas 2 a 6 como no capítulo anterior.

• Inicie o XCode e clique em Arquivo -> Abrir

• Escolha o projeto xcode no diretório ios do nosso projeto flutter.

• Abra AppDelegate.m em Runner -> Caminho do Runner. Ele contém o seguinte


código:

#include "AppDelegate.h"
#include "GeneratedPluginRegistrant.h"

@implementação AppDelegate

- (BOOL)aplicativo:(UIApplication *)aplicativo
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

//

[GeneratedPluginRegistrant RegisterWithRegistry:self];
// Substituir ponto para personalização após inicialização do aplicativo.
return [super aplicativo: aplicativo
didFinishLaunchingWithOptions:launchOptions];
}

@fim

• Adicionamos um método openBrowser para abrir o navegador com o URL especificado. Isto
aceita um único argumento, url.

- (void)openBrowser:(NSString *)urlString {
NSURL *url = [NSURL URLWithString:urlString];
UIApplication *application = [UIApplication sharedApplication];

[aplicativo openURL:url];
}

• No método didFinishLaunchingWithOptions, encontre o controlador e defina-o no controlador


variável.

100
Machine Translated by Google

Vibração

Controlador FlutterViewController* =
(FlutterViewController*)self.window.rootViewController;

• No método didFinishLaunchingWithOptions, defina o canal do navegador como


flutterapp.tutorialspoint.com/browse:

FlutterMethodChannel* navegadorChannel = [FlutterMethodChannel

métodoChannelWithName:@"flutterapp.tutorialspoint.com/browser"
binárioMessenger:controlador];

• Crie uma variável, fracaSelf e defina a classe atual:

__tipo fraco(self) fracoSelf = self;

• Agora, implemente setMethodCallHandler. Chame openBrowser combinando call.method.


Obtenha o URL invocando call.arguments e passe-o ao chamar o openBrowser.

[browserChannel setMethodCallHandler:^(chamada FlutterMethodCall*, resultado


FlutterResult) { if
([@"openBrowser" isEqualToString:call.method]) { NSString *url =
call.arguments[@"url"];

[fracoSelf openBrowser:url]; } else

{ resultado(FlutterMethodNotImplemented);
}
}];

• O código completo é o seguinte:

#include "AppDelegate.h"
#include "GeneratedPluginRegistrant.h"

@implementação AppDelegate

- (BOOL)aplicativo:(UIApplication *)aplicativo
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

//o código personalizado inicia


Controlador FlutterViewController* =
(FlutterViewController*)self.window.rootViewController;

FlutterMethodChannel* navegadorChannel = [FlutterMethodChannel

métodoChannelWithName:@"flutterapp.tutorialspoint.com/browser"
binárioMessenger:controlador];

__tipo fraco(self) fracoSelf = self; [browserChannel


setMethodCallHandler:^(chamada FlutterMethodCall*,
Resultado FlutterResult) {
if ([@"openBrowser" isEqualToString:call.method]) { NSString *url =
call.arguments[@"url"];

101
Machine Translated by Google

Vibração

[fracoSelf openBrowser:url]; } else

{ resultado(FlutterMethodNotImplemented);
}
}];

// o código personalizado termina

[GeneratedPluginRegistrant RegisterWithRegistry:self]; // Substituir


ponto para personalização após inicialização do aplicativo. return [super
aplicativo: aplicativo
didFinishLaunchingWithOptions:launchOptions]; }

- (void)openBrowser:(NSString *)urlString {
NSURL *url = [NSURL URLWithString:urlString];
UIApplication *application = [UIApplication sharedApplication];

[aplicativo openURL:url];
}

@fim

• Abra a configuração do projeto.

• Vá para Capacidades e ative os modos de segundo plano

• Adicionar *Busca em segundo plano e Notificação remota**

• Agora, execute o aplicativo. Funciona de forma semelhante à versão Android, mas o navegador Safari
será aberto em vez do Chrome.

102
Machine Translated by Google

13. Flutter – Introdução ao Pacote Vibração

A maneira do Dart organizar e compartilhar um conjunto de funcionalidades é por meio do Package. O pacote Dart consiste
simplesmente em bibliotecas ou módulos compartilháveis. Em geral, o pacote Dart é igual ao aplicativo Dart, exceto que o
pacote Dart não possui ponto de entrada do aplicativo, principal.

A estrutura geral do pacote (considere um pacote demo, my_demo_package) é a seguinte:

• lib/src/* : Arquivos de código Dart privados.

• lib/my_demo_package.dart: arquivo de código principal do Dart . Pode ser importado para um


aplicação como:

importar 'pacote: meu_demo_package/my_demo_package.dart'

• Outro arquivo de código privado pode ser exportado para o arquivo de código principal
(my_demo_package.dart), se necessário, conforme mostrado abaixo:

exportar src/meu_código_privado.dart

• lib/* : qualquer número de arquivos de código Dart organizados em qualquer estrutura de pastas personalizada.
O código pode ser acessado como,

importar 'pacote: meu_demo_package/custom_folder/custom_file.dart'

• pubspec.yaml: Especificação do projeto, igual à da aplicação.

Todos os arquivos de código Dart no pacote são simplesmente classes Dart e não há nenhum requisito especial para um
código Dart incluí-lo em um pacote.

Tipos de pacotes
Como os pacotes Dart são basicamente uma pequena coleção de funcionalidades semelhantes, eles podem ser categorizados
com base em sua funcionalidade.

Pacote Dardo
Código Dart genérico, que pode ser usado tanto em ambiente web quanto móvel. Por exemplo, english_words é um desses
pacotes que contém cerca de 5.000 palavras e possui funções utilitárias básicas como substantivos (listar substantivos em
inglês), sílabas (especificar o número de sílabas em uma palavra.

Pacote Flutter
Código Dart genérico, que depende do framework Flutter e pode ser usado apenas em ambiente móvel. Por exemplo, fluro é
um roteador personalizado para flutter. Depende da vibração
estrutura.

103
Machine Translated by Google

Vibração

Plug-in Flutter
Código Dart genérico, que depende da estrutura Flutter, bem como do código da plataforma subjacente (Android SDK ou iOS SDK). Por
exemplo, câmera é um plugin para interagir com a câmera do dispositivo. Depende da estrutura Flutter, bem como da estrutura
subjacente para obter acesso à câmera.

Usando um pacote Dart


Os pacotes Dart são hospedados e publicados no servidor ativo, https://pub.dartlang.org.
Além disso, o Flutter fornece uma ferramenta simples, pub, para gerenciar pacotes Dart no aplicativo. As etapas necessárias
para usar como pacote são as seguintes:

• Inclua o nome do pacote e a versão necessária no pubspec.yaml conforme mostrado


abaixo:

dependências:
palavras_inglês: ^3.1.5

• O número da versão mais recente pode ser encontrado verificando o servidor online.

• Instale o pacote no aplicativo usando o seguinte comando:

pacotes flutter são obtidos

• Durante o desenvolvimento no Android Studio, o Android Studio detecta qualquer alteração no pubspec.yaml e exibe
um alerta de pacote do Android Studio para o desenvolvedor, conforme mostrado abaixo:

• Os pacotes Dart podem ser instalados ou atualizados no Android Studio usando as opções do menu.

• Importe o arquivo necessário usando o comando mostrado abaixo e comece a trabalhar:

importar 'pacote:english_words/english_words.dart';

• Use qualquer método disponível no pacote,

substantivos.take(50).forEach(print);

• Aqui, usamos a função de substantivos para obter e imprimir as 50 principais palavras.

Desenvolva um pacote de plug-in Flutter


Desenvolver um plug-in Flutter é semelhante a desenvolver um aplicativo Dart ou pacote Dart. A única exceção é que o plugin
usará a API do sistema (Android ou iOS) para obter a funcionalidade específica da plataforma necessária.

Como já aprendemos como acessar o código da plataforma nos capítulos anteriores, vamos desenvolver um plugin simples,
my_browser, para entender o processo de desenvolvimento do plugin. O

104
Machine Translated by Google

Vibração

A funcionalidade do plugin my_browser é permitir que o aplicativo abra um determinado site no navegador
específico da plataforma.

• Inicie o Android Studio

• Clique em Arquivo -> Novo projeto Flutter e selecione a opção Flutter Plugin.

• Você pode ver uma janela de seleção do plugin Flutter conforme mostrado aqui:

• Insira my_browser como nome do projeto e clique em Avançar.

105
Machine Translated by Google

Vibração

• Insira o nome do plugin e outros detalhes na janela conforme mostrado aqui:

• Insira o domínio da empresa, flutterplugins.tutorialspoint.com na janela mostrada abaixo e clique em Concluir. Ele irá
gerar um código de inicialização para desenvolver nosso novo plugin.

106
Machine Translated by Google

Vibração

• Abra o arquivo my_browser.dart e escreva um método, openBrowser para invocar a plataforma


método openBrowser específico.

Future<void> openBrowser(String urlString) assíncrono {


tente
{ final int resultado = await _channel.invokeMethod('openBrowser', <String, String>{

'url': urlString });

} em PlatformException captura (e) {


// Não é possível abrir o navegador
print(e);
}
}

• Abra o arquivo MyBrowserPlugin.java e importe as seguintes classes:

importar android.app.Activity; importar


android.content.Intent; importar
android.net.Uri; importar
android.os.Bundle;

• Aqui, temos que importar a biblioteca necessária para abrir um navegador do Android.

• Adicionar nova variável privada mRegistrar do tipo Registrar na classe MyBrowserPlugin.

Registrador final privado mRegistrar;

• Aqui, o Registrador é usado para obter informações de contexto do código de chamada.

• Adicione um construtor para definir Registrar na classe MyBrowserPlugin.

private MyBrowserPlugin(Registrador registrador)


{ this.mRegistrar = registrador; }

• Altere registerWith para incluir nosso novo construtor na classe MyBrowserPlugin.

public static void registerWith (registrador de registrador) { canal final


MethodChannel = novo MethodChannel (registrar.messenger (),
"meu_navegador");
Instância MyBrowserPlugin = new MyBrowserPlugin(registrador);
canal.setMethodCallHandler(instância);
}

• Altere o onMethodCall para incluir o método openBrowser na classe MyBrowserPlugin.

@Override
public void onMethodCall(MethodCall call, Result result) {

String url = call.argument("url");

107
Machine Translated by Google

Vibração

if (call.method.equals("getPlatformVersion")) { result.success("Android
" + android.os.Build.VERSION.RELEASE); } else if (call.method.equals("openBrowser")) {

openBrowser(chamada, resultado, url); } else

{ resultado.notImplemented();
}
}

• Escreva o método openBrowser específico da plataforma para acessar o navegador em


Classe MyBrowserPlugin:

private void openBrowser(MethodCall call, Resultado resultado, String url) {


Atividade atividade = mRegistrar.activity(); if (activity == null)

{ result.error("ACTIVITY_NOT_AVAILABLE", "O navegador não pode ser aberto sem atividade


em primeiro plano", null); retornar;

Intenção intenção = nova Intent(Intent.ACTION_VIEW);


intent.setData(Uri.parse(url));

atividade.startActivity(intenção);
resultado.sucesso((Objeto) verdadeiro);
}

• O código-fonte completo do plugin my_browser é o seguinte:

meu_navegador.dart

importar 'dardo: assíncrono';

importar 'pacote:flutter/services.dart';

class Meu navegador {


static const MethodChannel _channel = const
MethodChannel('meu_navegador');

static Future<String> obter platformVersion async {


versão final da String = await
_channel.invokeMethod('getPlatformVersion'); versão de retorno;

Future<void> openBrowser(String urlString) assíncrono {


tente
{ final int resultado = await _channel.invokeMethod('openBrowser',
<String, String>{ 'url':
urlString });

} em PlatformException captura (e) {


// Não é possível abrir o navegador print(e);

108
Machine Translated by Google

Vibração

}
}

MeuBrowserPlugin.java

pacote com.tutorialspoint.flutterplugins.my_browser;

importar io.flutter.plugin.common.MethodCall; importar


io.flutter.plugin.common.MethodChannel; importar
io.flutter.plugin.common.MethodChannel.MethodCallHandler; importar
io.flutter.plugin.common.MethodChannel.Result; importar
io.flutter.plugin.common.PluginRegistry.Registrar;

importar android.app.Activity; importar


android.content.Intent; importar
android.net.Uri; importar
android.os.Bundle;

/** MyBrowserPlugin */ classe


pública MyBrowserPlugin implementa MethodCallHandler {
Registrador final privado mRegistrar;

private MyBrowserPlugin(Registrador registrador) { this.mRegistrar


= registrador;
}

/** Registro do plug-in. */ public static


void registerWith(registrador de registro) { canal final MethodChannel = new
MethodChannel(registrar.messenger(), "my_browser"); Instância MyBrowserPlugin = new

MyBrowserPlugin(registrador); canal.setMethodCallHandler(instância);

@Override
public void onMethodCall(MethodCall call, Result result) {
String url = call.argument("url");

if (call.method.equals("getPlatformVersion")) { result.success("Android
" + android.os.Build.VERSION.RELEASE); } else if (call.method.equals("openBrowser"))
{
openBrowser(chamada, resultado, url); }
else
{ resultado.notImplemented();
}
}

private void openBrowser(MethodCall call, Resultado resultado, String url) {


Atividade atividade = mRegistrar.activity(); if (atividade ==
nulo) {
result.error("ACTIVITY_NOT_AVAILABLE", "O navegador não pode ser aberto
sem atividade em primeiro plano", null); return;

109
Machine Translated by Google

Vibração

Intenção intenção = nova Intent(Intent.ACTION_VIEW);


intent.setData(Uri.parse(url));

atividade.startActivity(intenção);
resultado.sucesso((Objeto) verdadeiro);
}
}

• Crie um novo projeto, my_browser_plugin_test para testar nosso plugin recém-criado.

• Abra pubspec.yaml e defina my_browser como uma dependência de plugin:

dependências:
vibração:
SDK: vibração

meu_navegador:
caminho: ../meu_navegador

• O Android Studio alertará que pubspec.yaml foi atualizado conforme mostrado no alerta de pacote do Android
Studio fornecido abaixo:

• Clique na opção Obter dependências. O Android Studio obterá o pacote da Internet e o configurará
adequadamente para o aplicativo.

• Abra main.dart e inclua o plugin my_browser conforme abaixo:

importar 'pacote:meu_browser/meu_browser.dart';

• Chame a função openBrowser do plugin my_browser conforme mostrado abaixo:

onPressed: () => MyBrowser().openBrowser("https://flutter.dev"),

• O código completo do main.dart é o seguinte:

importar 'pacote:flutter/material.dart'; importar


'pacote:meu_browser/meu_browser.dart';

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

class MyApp estende StatelessWidget { @override

Construção de widget (contexto BuildContext) {


return MaterialApp(título:
'Flutter Demo', tema:

ThemeData(primárioSwatch:

Colors.blue, ), home: MyHomePage(título: 'Página inicial da


demonstração Flutter'), );

110
Machine Translated by Google

Vibração

}
}

class MyHomePage estende StatelessWidget


{ MyHomePage({Key key, this.title}): super(key: key);

título final da String;

@override
Widget build (contexto BuildContext) { return
Scaffold( appBar:
AppBar( title:
Text(this.title), ), body:

Center( child:
RaisedButton( child:
Text('Open Browser'), onPressed: ()
= > MeuBrowser().openBrowser("https://flutter.dev"), ), ), );

}
}

111
Machine Translated by Google

Vibração

• Execute o aplicativo e clique no botão Abrir navegador e veja se o navegador é iniciado. Você pode ver um aplicativo de
navegador - página inicial conforme mostrado na captura de tela abaixo:

112
Machine Translated by Google

Vibração

• Você pode ver um aplicativo de navegador - tela do navegador conforme mostrado na captura de tela mostrada
abaixo:

113
Machine Translated by Google

Vibração
14. Flutter – Acessando API REST

Flutter fornece pacote http para consumir recursos HTTP. http é uma biblioteca baseada no futuro e usa recursos de espera
e assíncronos. Ele fornece muitos métodos de alto nível e simplifica o desenvolvimento de aplicativos móveis baseados em
REST.

Conceitos Básicos
O pacote http fornece uma classe de alto nível e http para fazer solicitações da web.

• A classe http fornece funcionalidade para executar todos os tipos de solicitações HTTP.

• Os métodos http aceitam uma URL e informações adicionais através do Dart Map (dados de postagem, cabeçalhos
adicionais, etc.). Ele solicita o servidor e coleta a resposta de volta no padrão assíncrono/aguardado. Por exemplo,
o código abaixo lê os dados do URL especificado e os imprime no console.

print(aguarde http.read('https://flutter.dev/'));

Alguns dos métodos principais são os seguintes:

• read - Solicita a url especificada através do método GET e retorna a resposta como Future<String>

• get - Solicita a url especificada através do método GET e retorna a resposta como Future<Response>. Response é
uma classe que contém as informações da resposta.

• post - Solicite a url especificada através do método POST postando os dados fornecidos e retorne a resposta como
Future<Response>

• put - Solicita o URL especificado através do método PUT e retorna a resposta


como Futuro<Resposta>

• head - Solicita a url especificada através do método HEAD e retorna o


resposta como Future<Resposta>

• delete - Solicita a url especificada através do método DELETE e retorna o


resposta como Future<Resposta>

http também fornece uma classe de cliente HTTP mais padrão, client. cliente suporta conexão persistente. Será útil quando
houver muitas solicitações a serem feitas a um servidor específico. Ele precisa ser fechado corretamente usando o método
close. Caso contrário, é semelhante à classe http. O código de exemplo é o seguinte:

var cliente = new http.Cliente();


tentar {
print(aguarde client.get('https://flutter.dev/'));
} finalmente {
cliente.close();
}

114
Machine Translated by Google

Vibração

Acessando ProductserviceAPI
Vamos criar um aplicativo simples para obter dados de produtos de um servidor web e depois mostrar os produtos
usando ListView.

• Crie um novo aplicativo Flutter no Android Studio, product_rest_app

• Substitua o código de inicialização padrão (main.dart) pelo nosso código product_nav_app .

• Copie a pasta de ativos de product_nav_app para product_rest_app e adicione ativos


dentro do arquivo pubspec.yaml

vibração:

ativos:
- assets/appimages/floppy.png - assets/
appimages/iphone.png - assets/
appimages/laptop.png - assets/
appimages/pendrive.png - assets/
appimages/pixel.png - assets/
appimages/tablet.png

• Configure o pacote http no arquivo pubspec.yaml conforme mostrado abaixo:

dependências:
http: ^0.12.0+2

• Aqui, usaremos a versão mais recente do pacote http. O Android Studio enviará um alerta de pacote
informando que pubspec.yaml foi atualizado.

• Clique na opção Obter dependências. O Android Studio obterá o pacote da Internet e o configurará
adequadamente para o aplicativo.

• Importe o pacote http no arquivo main.dart:

importar 'dardo: assíncrono';


importar 'dardo:converter';
importar 'pacote:http/http.dart' como http;

• Crie um novo arquivo JSON, products.json com informações do produto conforme mostrado abaixo:

[
{
"name": "iPhone",
"description": "iPhone é o telefone estilista de todos os tempos",
"price": 1000,
"image": "iphone.png"
},
{
"name": "Pixel",
"description": "Pixel é o telefone com mais recursos de todos os tempos",
"price": 800,
"image": "pixel.png"

115
Machine Translated by Google

Vibração

},
{
"name": "Laptop",
"description": "Laptop é a ferramenta de desenvolvimento mais produtiva", "price": 2000,
"image": "laptop.png"

},
{
"name": "Tablet",
"description": "Tablet é o dispositivo mais útil para reuniões", "price": 1500, "image": "tablet.png"

},
{
"name": "Pendrive",
"description": "Pendrive é um meio de armazenamento útil", "price": 100,
"image":
"pendrive.png"
},
{
"name": "Unidade de disquete",
"description": "A unidade de disquete é um meio de armazenamento de resgate útil", "price":
20, "image":
"floppy.png"
}
]

• Crie uma nova pasta, JSONWebServer e coloque o arquivo JSON, products.json.

• Execute qualquer servidor web com JSONWebServer como diretório raiz e obtenha seu caminho web.
Por exemplo, http://192.168.184.1:8000/products.json. Podemos usar qualquer servidor web como apache, nginx
etc.,

• A maneira mais fácil é instalar um aplicativo de servidor http baseado em nó. Siga os passos dados
abaixo para instalar e executar o aplicativo de servidor http.

• Instale o aplicativo Nodejs (https://nodejs.org/en/)


• Vá para a pasta JSONWebServer.

cd /caminho/para/JSONWebServer

• Instale o pacote http-server usando npm

npm install -g servidor http

• Agora, execute o servidor.

servidor http . -p 8000

Iniciando o servidor http, servindo .


Disponível em:
http://192.168.99.1:8000 http://
192.168.1.2:8000

116
Machine Translated by Google

Vibração

http://127.0.0.1:8000
Pressione CTRL-C para parar o servidor

• Crie um novo arquivo, Product.dart na pasta lib e mova a classe Product para ele.

• Escreva um construtor de fábrica na classe Product, Product.fromMap, para converter o mapa de dados
mapeado no objeto Product. Normalmente, o arquivo JSON será convertido em objeto Dart Map e,
em seguida, convertido em objeto relevante (Produto)

fábrica Produto.fromJson(Map<String, dinâmico> dados) {


return

Produto(dados['nome'],
dados['descrição'],
dados['preço'],
dados['imagem'], );
}

• O código completo do Product.dart é o seguinte:

classe Produto
{ final String nome;
descrição final da String; preço
interno final; imagem
final da String;

Produto(este.nome, esta.descrição, este.preço, esta.imagem);

fábrica Product.fromMap(Map<String, dynamic> json) { return


Product( json['nome'],
json['descrição'],
json['preço'],
json['imagem'], );

}
}

• Escreva dois métodos - parseProducts e fetchProducts - na classe principal para buscar e carregar as
informações do produto do servidor web no objeto List<Product>.

List<Produto> parseProducts(String responseBody) { final


analisado = json.decode(responseBody).cast<Map<String, dynamic>>(); retornar
analisado.map<Produto>((json) => Produto.fromJson(json)).toList();
}

Future<Lista<Produto>> fetchProducts() async {


resposta final = aguardar
http.get('http://192.168.1.2:8000/products.json');

if (response.statusCode == 200) {
return parseProducts(response.body); } else
{ throw
Exception('Não foi possível buscar produtos da API REST');

117
Machine Translated by Google

Vibração

}
}

• Observe os seguintes pontos aqui:

• Future é usado para carregar lentamente as informações do produto. O carregamento lento é um conceito para adiar
a execução do código até que seja necessário.

• http.get é usado para buscar os dados da Internet.

• json.decode é usado para decodificar os dados JSON no objeto Dart Map. Depois que os dados JSON forem
decodificados, eles serão convertidos em List<Product> usando fromMap da classe Product.

• Na classe MyApp, adicione uma nova variável de membro, produtos do tipo Future<Product> e inclua-a no construtor.

class MyApp estende StatelessWidget {


produtos finais Future<List<Product>>;

MyApp({Key key, this.products}): super(key: key);

...

• Na classe MyHomePage, adicione novos produtos variáveis de membro do tipo Future<Product> e inclua-os no
construtor. Além disso, remova a variável items e seu método relevante, chamada do método getProducts.
Colocando a variável produtos no construtor. Permitirá buscar os produtos na Internet apenas uma vez, quando o
aplicativo for iniciado pela primeira vez.

class MyHomePage estende StatelessWidget {


título final da String;
produtos finais Future<List<Product>>;

MyHomePage({Chave-chave, this.title, this.products}): super(key: key);


...

• Altere a opção inicial (MyHomePage) no método de construção do widget MyApp para


acomodar as alterações acima:

home: MinhaPáginaHome(
título: 'Página inicial de demonstração de navegação de produto',
produtos: produtos),

• Altere a função principal para incluir argumentos Future<Product>:

void main() => runApp(MyApp(fetchProduct()));

• Crie um novo widget, ProductBoxList para construir a lista de produtos na página inicial.

class ProductBoxList estende StatelessWidget {


lista final<Produto> itens;

118
Machine Translated by Google

Vibração

ProductBoxList({Chave-chave, this.items});

@override
Widget build (contexto BuildContext) { return
ListView.builder (
itemCount: items.length, itemBuilder:
(contexto, índice) { return GestureDetector( filho:
ProductBox(item: itens[índice]),
onTap: () { Navigator.push( context, MaterialPageRoute(

construtor: (contexto) => ProductPage(item: itens[índice]), ), ); }, ); }, );

}
}

Observe que usamos o mesmo conceito usado no aplicativo Navigation para listar o produto, exceto que ele foi projetado
como um widget separado, passando produtos (objeto) do tipo List<Product>.

• Por fim, modifique o método de construção do widget MyHomePage para obter as informações do
produto usando a opção Future em vez da chamada de método normal.

Construção de widget (contexto BuildContext) {


return Scaffold( appBar:
AppBar(title: Text("Navegação do Produto")), body: Center(

filho: FutureBuilder<List<Produto>>( futuro: produtos,


construtor: (contexto,
instantâneo) {
if (instantâneo.hasError) imprimir(instantâneo.error);

retornar snapshot.hasData?
ProductBoxList( items:
snapshot.data) // retorna o widget ListView
: Centro(filho: CircularProgressIndicator());

}, ), ));
}

• Observe aqui que usamos o widget FutureBuilder para renderizar o widget. Construtor do Futuro
tentará buscar os dados de sua propriedade futura (do tipo Future<List<Product>>).
Se a propriedade futura retornar dados, ela renderizará o widget usando ProductBoxList, caso contrário,
gerará um erro.

119
Machine Translated by Google

Vibração

• O código completo do main.dart é o seguinte:

importar 'pacote:flutter/material.dart';

importar 'dardo: assíncrono';


importar 'dardo:converter';
importar 'pacote:http/http.dart' como http;

importar 'Produto.dart';

void main() => runApp(MyApp(produtos: fetchProducts()));

List<Produto> parseProducts(String responseBody) { final analisado


= json.decode(responseBody).cast<Map<String, dynamic>>(); retornar
analisado.map<Produto>((json) => Produto.fromMap(json)).toList();
}

Future<Lista<Produto>> fetchProducts() async {


resposta final = aguardar
http.get('http://192.168.1.2:8000/products.json');

if (response.statusCode == 200) {
return parseProducts(response.body); } else
{ throw
Exception('Não foi possível buscar produtos da API REST');
}
}

class MyApp estende StatelessWidget {


produtos finais Future<List<Product>>;

MyApp({Key key, this.products}): super(key: key);

// Este widget é a raiz da sua aplicação. @override Compilação


do widget
(contexto BuildContext) {
return MaterialApp( título:
'Flutter Demo', tema:

ThemeData( primárioSwatch:

Colors.blue, ), home:
MyHomePage( título: 'Página inicial de demonstração de navegação de
produto',
produtos: produtos), );
}
}

class MyHomePage estende StatelessWidget { final String


title; produtos finais
Future<List<Product>>;

MyHomePage({Chave-chave, this.title, this.products}): super(key: key);

// itens finais = Product.getProducts();

120
Machine Translated by Google

Vibração

@sobrepor
Construção de widget (contexto BuildContext)
{ return Scaffold( appBar:
AppBar(title: Text("Navegação do produto")), body: Center( child:

FutureBuilder<List<Product>>( future: products, builder:


(context, snapshot) {

if (instantâneo.hasError) imprimir(instantâneo.error);

retornar snapshot.hasData?
ProductBoxList( items:
snapshot.data) // retorna o widget ListView
: Centro(filho: CircularProgressIndicator());

}, ), ));
}
}

class ProductBoxList estende StatelessWidget {


lista final<Produto> itens;

ProductBoxList({Chave-chave, this.items});

@override
Widget build (contexto BuildContext) { return
ListView.builder (
itemCount: items.length,
itemBuilder: (contexto, índice) { return
GestureDetector( filho:
ProductBox(item: itens[índice]), onTap: ()

{ Navigator.push( context,

MaterialPageRoute(
construtor: (contexto) => ProductPage(item: itens[índice]), ), ); }, ); }, );

}
}

class ProductPage estende StatelessWidget {


ProductPage({chave-chave, this.item}): super(chave: chave);

item final do Produto;

@sobrepor
Construção de widget (contexto BuildContext)
{ return Scaffold (

121
Machine Translated by Google

Vibração

appBar: AppBar
(título: Texto (este.item.nome),),

corpo: Centro
(filho: Container
(preenchimento: EdgeInsets.all (0),
filho: Coluna
(mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start, filhos:
<Widget>[Image.asset("assets/
appimages/" + this.item.image), Expanded( filho:

Container( preenchimento:
EdgeInsets.all(5), filho:

Column( mainAxisAlignment:
MainAxisAlignment.spaceEvenly,
filhos: <Widget>[
Text(este.item.nome,
estilo: TextStyle(fontWeight:
Intensidade da fonte: Negrito)),
Text(this.item.description),
Text("Preço: " + this.item.price.toString()), RatingBox(), ], )))

]),

), ), );
}
}

class RatingBox estende StatefulWidget { @override

_RatingBoxState createState() => _RatingBoxState();


}

classe _RatingBoxState estende State<RatingBox> {


int _classificação = 0;

void _setRatingAsOne()
{ setState(()
{ _rating = 1; });

void _setRatingAsTwo()
{ setState(()
{ _rating = 2; });

void _setRatingAsThree()
{ setState(() {

122
Machine Translated by Google

Vibração

_classificação =
3; });
}

Construção de widget (contexto BuildContext) {


duplo _tamanho = 20;
imprimir(_classificação);

return
Row( mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.end, mainAxisSize:
MainAxisSize.max, filhos:

<Widget>[ Container( preenchimento:


EdgeInsets.all(0), filho: IconButton(
ícone: (_rating >= 1 ? Ícone

(Ícones.estrela, tamanho:
_tamanho,
)
:
Icon( Icons.star_border, tamanho:
_size, )), cor:

Colors.red[500], onPressed:
_setRatingAsOne, iconSize: _size, ), ),
Container( preenchimento:

EdgeInsets.all(0),
filho: IconButton(

ícone: (_rating >= 2 ? Ícone

(Ícones.estrela, tamanho:
_tamanho,
)
: Ícone
( Icons.star_border,
tamanho: _size, )),
cor:
Colors.red [500], onPressed:
_setRatingAsTwo, iconSize: _size, ), ),
Container ( preenchimento:

EdgeInsets.all
(0), filho: IconButton (

ícone: (_rating >= 3 ? Ícone

(Ícones.estrela, tamanho:
_tamanho,
)

123
Machine Translated by Google

Vibração

:
Icon( Icons.star_border,
size: _size, )),

color: Colors.red[500],
onPressed: _setRatingAsThree,
iconSize: _size, ), ), ], );

}
}

classe ProductBox estende StatelessWidget {


ProductBox({chave-chave, this.item}): super(chave: chave);

item final do Produto;

Construção de widget (contexto BuildContext)


{ return
Container( preenchimento:
EdgeInsets.all(2),
altura: 140,
filho: Cartão( filho: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly, filhos:

<Widget>[ Image.asset("assets/appimages/" + this.item.image),

Expanded( child:
Container( padding: EdgeInsets.all(5),
child:

Column( mainAxisAlignment :
MainAxisAlignment.spaceEvenly, filhos: <Widget>[
Text(este.item.nome,
estilo: TextStyle(fontWeight:
Intensidade da fonte: Negrito)),
Text(this.item.description),
Text("Preço: " + this.item.price.toString()), RatingBox(), ], )))

]),
));
}
}

Por fim, execute o aplicativo para ver o resultado. Será igual ao nosso exemplo de navegação , exceto que
os dados são da Internet, em vez de dados estáticos locais inseridos durante a codificação do aplicativo.

124
Machine Translated by Google

Vibração
15. Flutter – Conceitos de banco de dados

Flutter fornece muitos pacotes avançados para trabalhar com bancos de dados. Os pacotes mais importantes são:

• sqflite – Usado para acessar e manipular banco de dados SQLite, e

• firebase_database – Usado para acessar e manipular banco de dados NoSQL hospedado na nuvem
do Google.

Neste capítulo, vamos discutir cada um deles em detalhes.

SQLite
O banco de dados SQLite é o mecanismo de banco de dados incorporado baseado em SQL padrão e de fato. É um
mecanismo de banco de dados pequeno e testado pelo tempo. O pacote sqflite fornece muitas funcionalidades para
trabalhar de forma eficiente com o banco de dados SQLite. Ele fornece métodos padrão para manipular o mecanismo de
banco de dados SQLite. A funcionalidade principal fornecida pelo pacote sqflite é a seguinte:

• Criar/Abrir (método openDatabase) um banco de dados SQLite.

• Execute a instrução SQL (método execute) no banco de dados SQLite.

• Métodos de consulta avançados (método de consulta) para reduzir o código necessário para consultar e
obter informações do banco de dados SQLite.

Vamos criar um aplicativo de produto para armazenar e buscar informações de produto de um mecanismo de banco de
dados SQLite padrão usando o pacote sqflite e entender o conceito por trás do banco de dados SQLite e do pacote sqflite.

• Crie um novo aplicativo Flutter no Android Studio, product_sqlite_app

• Substitua o código de inicialização padrão (main.dart) pelo nosso código product_rest_app .

• Copie a pasta de ativos de product_nav_app para product_rest_app e adicione ativos


dentro do arquivo *pubspec.yaml`

vibração:

ativos:
- assets/appimages/floppy.png
- ativos/appimages/iphone.png
- ativos/appimages/laptop.png
- assets/appimages/pendrive.png
- ativos/appimages/pixel.png
- ativos/appimages/tablet.png

• Configure o pacote sqflite no arquivo pubspec.yaml conforme mostrado abaixo:

dependências:
sqflite: qualquer

125
Machine Translated by Google

Vibração

Use o número da versão mais recente do sqflite no lugar de qualquer

• Configure o pacote path_provider no arquivo pubspec.yaml conforme mostrado abaixo:

dependências:
path_provider: qualquer

• Aqui, o pacote path_provider é usado para obter o caminho da pasta temporária do sistema e o caminho do
aplicativo. Use o número da versão mais recente do sqflite no lugar de qualquer.

• O Android Studio alertará que o pubspec.yaml foi atualizado.

• Clique na opção Obter dependências. O Android Studio obterá o pacote da Internet e o configurará
adequadamente para o aplicativo.

• No banco de dados, precisamos de chave primária, id como campo adicional junto com propriedades do
produto como nome, preço, etc., portanto, adicione a propriedade id na classe Produto. Além disso, adicione
um novo método, toMap, para converter o objeto produto em objeto Map. fromMap e toMap são usados
para serializar e desserializar o objeto Product e são usados em métodos de manipulação de banco de
dados.

classe Produto { final


int id; nome da
string final; descrição
final da String; preço interno final;
imagem final da String;

colunas finais estáticas = ["id", "nome", "descrição", "preço", "imagem"];

Produto(este.id, este.nome, esta.descrição, este.preço, esta.imagem);

fábrica Product.fromMap(Map<String, dynamic> data) { return


Product( dados['id'],
dados['nome'],
dados['descrição'],
dados['preço'],
dados['imagem' ], );

Map<String, dinâmico> toMap() => { "id": id,


"nome":
nome, "descrição":
descrição, "preço": preço, "imagem":
imagem };

• Crie um novo arquivo, Database.dart na pasta lib para escrever funcionalidades relacionadas ao SQLite .

• Importe a instrução de importação necessária em Database.dart

126
Machine Translated by Google

Vibração

importar 'dardo: assíncrono';


importar 'dardo:io';
importar 'pacote:caminho/caminho.dart';

importar 'pacote:path_provider/path_provider.dart'; importar 'pacote:sqflite/


sqflite.dart';

importar 'Produto.dart';

• Observe os seguintes pontos aqui:

• async é usado para escrever métodos assíncronos.

• io é usado para acessar arquivos e diretórios.

• path é usado para acessar a função principal do utilitário Dart relacionada aos caminhos de arquivos.

• path_provider é usado para obter o caminho temporário e do aplicativo.

• sqflite é usado para manipular o banco de dados SQLite.

• Crie uma nova classe SQLiteDbProvider

• Declare um objeto SQLiteDbProvider estático baseado em singleton conforme especificado abaixo:

classe SQLiteDbProvider
{ SQLiteDbProvider._();

final estático SQLiteDbProvider db = SQLiteDbProvider._();

Banco de dados estático _banco de dados;


}

• O objeto SQLiteDBProvoider e seu método podem ser acessados através do banco de dados estático
variável.

SQLiteDBProvoider.db.<emthod>

• Crie um método para obter banco de dados (opção Future) do tipo Future<Database>.
Crie a tabela de produtos e carregue os dados iniciais durante a criação do próprio banco de dados.

Future<banco de dados> obtém banco de dados


assíncrono { if (_database !=
null) return _database;

_database = aguarda initDB(); retornar


_banco de dados;
}

initDB() assíncrono {
Documentos do diretórioDiretório = aguardar
getApplicationDocumentsDirectory(); String caminho
= join(documentsDirectory.path, "ProductDB.db"); return aguarda openDatabase(caminho,
versão: 1,

127
Machine Translated by Google

Vibração

onOpen: (db) {},


onCreate: (banco de dados de banco de dados, versão int) async {

aguarde db.execute("CREATE TABLE Produto ("


"id CHAVE PRIMÁRIA INTEIRA,"
"nome TEXTO,"
"texto de descrição,"
"preço INTEIRO,"
"imagem TEXTO"
")");

aguarde db.execute (
"INSERT INTO Produto ('id', 'nome', 'descrição', 'preço',
'imagem') valores (?, ?, ?, ?, ?)",
[1, "iPhone", "iPhone é o telefone estilista de todos os tempos", 1000,
"iphone.png"]);

aguarde db.execute (
"INSERT INTO Produto ('id', 'nome', 'descrição', 'preço',
'imagem') valores (?, ?, ?, ?, ?)",
[2, "Pixel", "Pixel é o telefone com mais recursos de todos os tempos", 800,
"pixel.png"]);

aguarde db.execute (
"INSERT INTO Produto ('id', 'nome', 'descrição', 'preço',
'imagem') valores (?, ?, ?, ?, ?)",
[3, "Laptop", "Laptop é a ferramenta de desenvolvimento mais produtiva",
2000, "laptop.png"]);

aguarde db.execute (
"INSERT INTO Produto ('id', 'nome', 'descrição', 'preço',
'imagem') valores (?, ?, ?, ?, ?)",
[4, "Tablet", "Laptop é a ferramenta de desenvolvimento mais produtiva",
1500, "tablet.png"]);

aguarde db.execute (
"INSERT INTO Produto ('id', 'nome', 'descrição', 'preço',
'imagem') valores (?, ?, ?, ?, ?)",
[5, "Pendrive", "Pendrive é um meio de armazenamento útil", 100, "pendrive.png"]);

aguarde db.execute (
"INSERT INTO Produto ('id', 'nome', 'descrição', 'preço',
'imagem') valores (?, ?, ?, ?, ?)",
[6, "Unidade de disquete", "A unidade de disquete é um meio de armazenamento de
resgate útil", 20, "floppy.png"]);
});
}

• Aqui, usamos os seguintes métodos:

• getApplicationDocumentsDirectory - Retorna o caminho do diretório do aplicativo

• join - Usado para criar um caminho específico do sistema. Nós o usamos para criar banco de dados

caminho.

128
Machine Translated by Google

Vibração

• openDatabase - Usado para abrir um banco de dados SQLite

• onOpen - Usado para escrever código ao abrir um banco de dados

• onCreate - Usado para escrever código enquanto um banco de dados é criado pela primeira vez

• db.execute - Usado para executar consultas SQL. Ele aceita uma consulta. Se a consulta tiver

espaço reservado (?), então aceita valores como lista no segundo argumento.

• Escreva um método para obter todos os produtos no banco de dados:

Future<Lista<Produto>> getAllProducts() async {


banco de dados final = aguarda banco de dados;

List<Map> results = await db.query("Produto", colunas: Product.columns, orderBy: "id ASC");

Lista<Produto> produtos = new Lista();


resultados.forEach((resultado) {
Produto produto = Produto.fromMap(resultado);
produtos.add(produto);
});

devolver produtos;
}

• Aqui, fizemos o seguinte:

• Método de consulta utilizado para buscar todas as informações do produto. query fornece um atalho para consultar
informações de uma tabela sem escrever a consulta inteira. query irá gerar a consulta adequada usando
nossas entradas como colunas, orderBy, etc.,

• Usei o método fromMap do produto para obter detalhes do produto repetindo os resultados
objeto, que contém todas as linhas da tabela.

• Escreva um método para obter o produto específico para id

Future<Produto> getProductById(int id) async {


banco de dados final = aguarda banco de dados;

var resultado = aguarda db.query("Produto", onde: "id = ", ondeArgs: [id]);

retornar resultado.isNotEmpty? Produto.fromMap(resultado.primeiro): Nulo;


}

• Aqui, usamos where e whereArgs para aplicar filtros.

• Crie três métodos - método de inserção, atualização e exclusão para inserir, atualizar e excluir produto do banco
de dados

insert(Produto produto) async {


banco de dados final = aguarda banco de dados;

var maxIdResult = aguarda db.rawQuery("SELECT MAX(id)+1 como last_inserted_id


FROM Product");

129
Machine Translated by Google

Vibração

var id = maxIdResult.first["last_inserted_id"];

var resultado = aguardar db.rawInsert(


"INSERIR no produto (id, nome, descrição, preço, imagem)"
"
VALORES (?, ?, ?, ?, ?)",
[id, nome do produto, descrição do produto, preço do produto,
Imagem do
Produto] );

resultado de retorno;
}

update(Produto produto) async { final db =


aguarda banco de dados;

var resultado = aguarda db.update("Produto", produto.toMap(), onde: "id =?",


ondeArgs: [produto.id]);

resultado de retorno;
}

delete(int id) async { final db =


aguarda banco de dados;

db.delete("Produto", onde: "id =?", whereArgs: [id]);


}

• O código final do Database.dart é o seguinte:

importar 'dardo: assíncrono';


importar 'dardo:io';
importar 'pacote:caminho/caminho.dart';

importar 'pacote:path_provider/path_provider.dart'; importar 'pacote:sqflite/


sqflite.dart';

importar 'Produto.dart';

classe SQLiteDbProvider
{ SQLiteDbProvider._();

final estático SQLiteDbProvider db = SQLiteDbProvider._();

Banco de dados estático _banco de dados;

Future<banco de dados> obtém banco de dados


assíncrono { if (_database != null)
return _database;

_database = aguarda initDB(); retornar


_banco de dados;
}

initDB() assíncrono {

130
Machine Translated by Google

Vibração

Documentos do diretórioDiretório = aguardar


getApplicationDocumentsDirectory();
String caminho = join(documentsDirectory.path, "ProductDB.db");
retornar aguarde openDatabase(
caminho,
versão 1,
onOpen: (db) {},
onCreate: (banco de dados de banco de dados, versão int) async {

aguarde db.execute("CREATE TABLE Produto ("


"id CHAVE PRIMÁRIA INTEIRA,"
"nome TEXTO,"
"texto de descrição,"
"preço INTEIRO,"
"imagem TEXTO"
")");

aguarde db.execute (
"INSERT INTO Produto ('id', 'nome', 'descrição', 'preço',
'imagem') valores (?, ?, ?, ?, ?)",
[1, "iPhone", "iPhone é o telefone estilista de todos os tempos", 1000,
"iphone.png"]);

aguarde db.execute (
"INSERT INTO Produto ('id', 'nome', 'descrição', 'preço',
'imagem') valores (?, ?, ?, ?, ?)",
[2, "Pixel", "Pixel é o telefone com mais recursos de todos os tempos", 800,
"pixel.png"]);

aguarde db.execute (
"INSERT INTO Produto ('id', 'nome', 'descrição', 'preço',
'imagem') valores (?, ?, ?, ?, ?)",
[3, "Laptop", "Laptop é a ferramenta de desenvolvimento mais produtiva",
2000, "laptop.png"]);

aguarde db.execute (
"INSERT INTO Produto ('id', 'nome', 'descrição', 'preço',
'imagem') valores (?, ?, ?, ?, ?)",
[4, "Tablet", "Laptop é a ferramenta de desenvolvimento mais produtiva",
1500, "tablet.png"]);

aguarde db.execute (
"INSERT INTO Produto ('id', 'nome', 'descrição', 'preço',
'imagem') valores (?, ?, ?, ?, ?)",
[5, "Pendrive", "Pendrive é um meio de armazenamento útil", 100, "pendrive.png"]);

aguarde db.execute (
"INSERT INTO Produto ('id', 'nome', 'descrição', 'preço',
'imagem') valores (?, ?, ?, ?, ?)",
[6, "Unidade de disquete", "A unidade de disquete é um meio de armazenamento de
resgate útil", 20, "floppy.png"]);
});
}

131
Machine Translated by Google

Vibração

Future<Lista<Produto>> getAllProducts() async {


banco de dados final = aguarda banco de dados;

List<Map> results = await db.query("Produto", colunas: Product.columns,


orderBy: "id ASC");

Lista<Produto> produtos = new Lista();


results.forEach((resultado) { Produto
produto = Produto.fromMap(resultado);
produtos.add(produto); });

devolver produtos;
}

Future<Produto> getProductById(int id) async {


banco de dados final = aguarda banco de dados;

var resultado = aguarda db.query("Produto", onde: "id = ", ondeArgs: [id]);

retornar resultado.isNotEmpty? Produto.fromMap(resultado.primeiro): Nulo;


}

insert(Produto produto) async { final db =


aguarda banco de dados;

var maxIdResult = aguarda db.rawQuery("SELECT MAX(id)+1 como


last_inserted_id FROM Product"); var id =
maxIdResult.first["last_inserted_id"];

var resultado = aguardar db.rawInsert(


"INSERIR no produto (id, nome, descrição, preço, imagem)"
"
VALORES (?, ?, ?, ?, ?)",
[id, nome do produto, descrição do produto, preço do produto,
Imagem do
Produto] );

resultado de retorno;
}

update(Produto produto) async { final db


= aguarda banco de dados;

var resultado = aguarda db.update("Produto", produto.toMap(), onde: "id =?",


ondeArgs: [produto.id]);

resultado de retorno;
}

delete(int id) async { final db


= aguarda banco de dados;

db.delete("Produto", onde: "id =?", whereArgs: [id]);

132
Machine Translated by Google

Vibração

}
}

• Altere o método principal para obter as informações do produto.

void principal() {
runApp(MyApp(produtos: SQLiteDbProvider.db.getAllProducts()));
}

• Aqui, usamos o método getAllProducts para buscar todos os produtos do banco de dados.

• Execute o aplicativo e veja os resultados. Será semelhante ao exemplo anterior, Acessando a API de serviço do produto,
exceto que as informações do produto são armazenadas e obtidas do banco de dados SQLite local.

Cloud Firestore
Firebase é uma plataforma de desenvolvimento de aplicativos BaaS. Ele fornece muitos recursos para acelerar o
desenvolvimento de aplicativos móveis, como serviço de autenticação, armazenamento em nuvem, etc.. Um dos
principais recursos do Firebase é o Cloud Firestore, um banco de dados NoSQL em tempo real baseado em nuvem.

Flutter fornece um pacote especial, cloud_firestore para programar com Cloud Firestore. Vamos criar uma loja de produtos
online no Cloud Firestore e criar um aplicativo para acessar a loja de produtos.

• Crie um novo aplicativo Flutter no Android Studio, product_firebase_app

• Substitua o código de inicialização padrão (main.dart) pelo nosso código product_rest_app .

• Copie o arquivo Product.dart de product_rest_app para a pasta lib.

classe Produto {
nome da string final;
descrição final da String;
preço interno final;
imagem final da String;

Produto(este.nome, esta.descrição, este.preço, esta.imagem);

fábrica Product.fromMap(Map<String, dinâmico> json) {


devolver Produto (
json['nome'],
json['descrição'],
json['preço'],
json['imagem'],
);
}
}

• Copie a pasta assets de product_rest_app para product_firebase_app e adicione assets dentro do arquivo
pubspec.yaml

vibração:

133
Machine Translated by Google

Vibração

ativos:
- assets/appimages/floppy.png
- ativos/appimages/iphone.png
- ativos/appimages/laptop.png
- assets/appimages/pendrive.png
- ativos/appimages/pixel.png
- ativos/appimages/tablet.png

• Configure o pacote cloud_firestore no arquivo pubspec.yaml conforme mostrado abaixo:

dependências:
nuvem_firestore: ^0.9.13+1

• Aqui, use a versão mais recente do pacote cloud_firestore.

• O Android Studio alertará que o pubspec.yaml foi atualizado conforme mostrado aqui:

• Clique na opção Obter dependências. O Android Studio obterá o pacote da Internet e o configurará
adequadamente para o aplicativo.

• Crie um projeto no Firebase usando as seguintes etapas:

• Criar a Base de fogo conta por selecionando Livre plano no


https://firebase.google.com/pricing/

• Depois que a conta do Firebase for criada, ela será redirecionada para a página de visão geral do projeto.
Ele lista todos os projetos baseados no Firebase e oferece uma opção para criar um novo projeto.

• Clique em Adicionar projeto e uma página de criação de projeto será aberta.

• Insira o banco de dados do aplicativo de produtos como nome do projeto e clique na opção Criar projeto.

• Acesse *Console do Firebase.

• Clique em Visão geral do projeto. Ele abre a página de visão geral do projeto.

• Clique no ícone do Android. Isso abrirá as configurações do projeto específicas para o desenvolvimento do Android.

• Insira o nome do pacote Android, com.tutorialspoint.flutterapp.product_firebase_app

• Clique em Registrar aplicativo. Ele gera um arquivo de configuração do projeto, google_service.json

• Baixe google_service.json e mova-o para o diretório android/app do projeto. Este arquivo é a conexão entre
nosso aplicativo e o Firebase.

• Abra android/app/build.gradle e inclua o seguinte código:

aplicar plug-in: 'com.google.gms.google-services'

• Abra android/build.gradle e inclua a seguinte configuração:

134
Machine Translated by Google

Vibração

buildscript
{ repositórios { // ...

dependências { // ...
classpath
'com.google.gms:google-services:3.2.1' // novo
}
}

Aqui, o plugin e o caminho da classe são usados para fins de leitura do arquivo google_service.json.

• Abra android/app/build.gradle e inclua também o código a seguir.

android
{ configuração padrão {
...
multiDexEnabled verdadeiro
}
...
}

dependências {
...
compilar 'com.android.support:multidex:1.0.3'
}

Essa dependência permite que o aplicativo Android use várias funcionalidades dex.

• Siga as etapas restantes no Firebase Console ou simplesmente pule-as.

• Crie uma loja de produtos no projeto recém-criado usando as seguintes etapas:

• Acesse o console do Firebase.

• Abra o projeto recém-criado.

• Clique na opção Banco de dados no menu esquerdo.

• Clique na opção Criar banco de dados.

• Clique em Iniciar no modo de teste e depois em Ativar

• Clique em Adicionar coleção. Insira o produto como nome da coleção e clique em Avançar.

• Insira as informações do produto de amostra conforme mostrado na imagem aqui:

135
Machine Translated by Google

Vibração

• Adicione informações adicionais do produto usando as opções Adicionar documento .

• Abra o arquivo main.dart e importe o arquivo do plugin Cloud Firestore e remova o pacote http.

importar 'pacote:cloud_firestore/cloud_firestore.dart';

• Remova parseProducts e atualize fetchProducts para buscar produtos da nuvem


Firestore em vez de API de serviço de produto

Stream<QuerySnapshot> fetchProducts() {
retornar Firestore.instance.collection('produto').snapshots();
}

• Aqui, o método Firestore.instance.collection é usado para acessar a coleção de produtos disponíveis no


armazenamento em nuvem. Firestore.instance.collection oferece muitas opções para filtrar a coleção para obter
os documentos necessários. Porém, não aplicamos nenhum filtro para obter todas as informações do produto.

• O Cloud Firestore fornece a coleta através do conceito Dart Stream e assim modifica o tipo de produto no widget MyApp
e MyHomePage de Future<list<Product>> para Stream<QuerySnapshot>.

136
Machine Translated by Google

Vibração

• Altere o método de construção do widget MyHomePage para usar StreamBuilder em vez de


Construtor do Futuro.

@sobrepor
Construção de widget (contexto BuildContext)
{ return
Scaffold( appBar: AppBar(title: Text("Navegação do produto")),
body:
Center( child: StreamBuilder<QuerySnapshot>( stream:
produtos, construtor:
(contexto, instantâneo) {
if (instantâneo.hasError) imprimir(instantâneo.error);

if(snapshot.hasData)
{ List<DocumentSnapshot> documentos = snapshot.data.documents;
List<Produto> itens = List<Produto>();

for(var i = 0; i <documents.length; i++) { DocumentSnapshot


documento = documentos[i];

itens.add(Product.fromMap(document.data));
}

return ProductBoxList(itens: itens); } else { return

Center(filho: CircularProgressIndicator());

} }, ), ));
}

• Aqui, buscamos as informações do produto como tipo List<DocumentSnapshot>.


Como nosso widget, ProductBoxList, não é compatível com documentos, convertemos os documentos
para o tipo List<Product> e os utilizamos posteriormente.

• Por fim, execute o aplicativo e veja o resultado. Como usamos as mesmas informações do produto do
aplicativo SQLite e alteramos apenas o meio de armazenamento, o aplicativo resultante parece idêntico
ao aplicativo SQLite .

137
Machine Translated by Google

16. Flutter – Internacionalização Vibração

Hoje em dia, as aplicações móveis são utilizadas por clientes de diferentes países e, como resultado, as aplicações são
obrigadas a exibir o conteúdo em diferentes idiomas. Permitir que um aplicativo funcione em vários idiomas é chamado de
Internacionalização do aplicativo.

Para que um aplicativo funcione em idiomas diferentes, ele deve primeiro encontrar a localidade atual
do sistema no qual o aplicativo está sendo executado e, em seguida, mostrar seu conteúdo nessa
localidade específica, e esse processo é chamado de Localização.

A estrutura Flutter fornece três classes base para localização e extensas classes de utilitários derivadas de classes base
para localizar um aplicativo.

As classes base são as seguintes:

• Locale - Locale é uma classe usada para identificar o idioma do usuário. Por exemplo, en-us
identifica o inglês americano e pode ser criado como:

Locale en_locale = Locale('en', 'US')

Aqui, o primeiro argumento é o código do idioma e o segundo argumento é o código do país.


Outro exemplo de criação de localidade Argentina Espanhol (es-ar) é o seguinte:

Locale es_locale = Locale('es', 'AR')

• Localizações - Localizações é um widget genérico usado para definir o local e os recursos localizados de seu
filho.

class CustomLocalizations {
CustomLocalizations(this.locale);

localidade final;

CustomLocalizations estáticos de (contexto BuildContext) {


return Localizations.of<CustomLocalizations>(contexto, CustomLocalizations);

Mapa estático<String, Mapa<String, String>> _resources = {


'pt': {
'título': 'Demonstração',
'mensagem': 'Olá mundo'
},
'é': {
'título': 'Manifestação',
'mensagem': 'Olá Mundo',
},
};

String obtém título {


return _resources[locale.idiomaCode]['título'];
}

138
Machine Translated by Google

Vibração

String receber mensagem {


return _resources[locale.idiomaCode]['mensagem'];
}
}

• Aqui, CustomLocalizations é uma nova classe customizada criada especificamente para obter determinado conteúdo
localizado (título e mensagem) para o widget. do método usa a classe Localizations para retornar a nova classe
CustomLocalizations.

• LocalizationsDelegate<T> - LocalizationsDelegate<T> é uma classe de fábrica por meio da qual o widget Localizations é
carregado. Possui três métodos substituíveis:

• isSupported - Aceita um código de idioma e retorna se o código de idioma especificado é


suportado ou não.

@sobrepor
bool isSupported(Locale locale) => ['en',
'es'].contains(locale.languageCode);

Aqui, o delegado funciona apenas para localidade en e es.

• load - Aceita uma localidade e começa a carregar os recursos para a localidade especificada.

@sobrepor
Future<CustomLocalizations> load(Locale locale) {
retornar
SynchronousFuture<CustomLocalizations>(CustomLocalizations(locale));
}

Aqui, o método load retorna CustomLocalizations. As CustomLocalizations retornadas podem ser usadas para
obter valores de título e mensagem em inglês e espanhol.

• ShouldReload - Especifica se o recarregamento de CustomLocalizations é necessário quando seu widget Localizations


é reconstruído.

@sobrepor
bool deveriaReload(CustomLocalizationsDelegate antigo) => falso;

• O código completo de CustomLocalizationDelegate é o seguinte:

classe CustomLocalizationsDelegate estende


LocalizationsDelegate<CustomLocalizations> {
const CustomLocalizationsDelegate();

@sobrepor
bool isSupported(Locale locale) => ['en',
'es'].contains(locale.idiomaCode);

@sobrepor
Future<CustomLocalizations> load(Locale locale) {
retornar
SynchronousFuture<CustomLocalizations>(CustomLocalizations(locale));

139
Machine Translated by Google

Vibração

@sobrepor
bool deveriaReload(CustomLocalizationsDelegate antigo) => falso;
}

Em geral, os aplicativos Flutter são baseados em dois widgets de nível raiz, MaterialApp ou WidgetsApp. Flutter fornece localização
pronta para ambos os widgets e eles são MaterialLocalizations e WidgetsLocaliations. Além disso, o Flutter também fornece
delegados para carregar MaterialLocalizations e GlobalMaterialLocalizations.delegate respectivamente.
WidgetsLocaliations e eles e são
GlobalWidgetsLocalizations.delegate

Vamos criar um aplicativo simples habilitado para internacionalização para testar e compreender o conceito.

• Crie um novo aplicativo flutter, flutter_localization_app

• Flutter suporta a internacionalização usando o pacote flutter exclusivo, flutter_localizations. A ideia é separar o conteúdo
localizado do SDK principal.
Abra pubspec.yaml e adicione o código abaixo para habilitar o pacote de internacionalização:

dependências:
vibração:
SDK: vibração
flutter_localizações:
SDK: vibração

• O Android Studio exibirá o seguinte alerta de que o pubspec.yaml foi atualizado.

• Clique na opção Obter dependências. O Android Studio obterá o pacote da Internet e o configurará adequadamente
para o aplicativo.

• Importe o pacote flutter_localizations no main.dart da seguinte forma:

importar 'pacote:flutter_localizations/flutter_localizations.dart';
importar 'pacote:flutter/foundation.dart' mostrar SynchronousFuture;

• Aqui, o objetivo do SynchronousFuture é carregar as localizações personalizadas de forma síncrona.

• Crie localizações personalizadas e seu delegado correspondente conforme especificado abaixo:

class CustomLocalizations {
CustomLocalizations(this.locale);

localidade final;

CustomLocalizations estáticos de (contexto BuildContext) {


return Localizations.of<CustomLocalizations>(contexto, CustomLocalizations);

140
Machine Translated by Google

Vibração

Mapa estático<String, Mapa<String, String>> _resources = {


'pt':
{ 'title': 'Demo',
'message': 'Hello World'
},
'es':
{ 'title': 'Manifestação', 'message':
'Olá Mundo',

}, };

String obtém título


{ return _resources[locale.idiomaCode]['título'];
}

String obter mensagem


{ return _resources[locale.languageCode]['message'];
}
}

classe CustomLocalizationsDelegate estende


LocalizationsDelegate<CustomLocalizations> { const
CustomLocalizationsDelegate();

@override
bool isSupported(Locale locale) => ['en',
'es'].contains(locale.idiomaCode);

@sobrepor
Future<CustomLocalizations> load(Locale locale) {
retornar
SynchronousFuture<CustomLocalizations>(CustomLocalizations(locale));
}

@override
bool deveriaReload(CustomLocalizationsDelegate antigo) => falso;
}

• Aqui, CustomLocalizations é criado para oferecer suporte à localização de título e mensagem no aplicativo
e CustomLocalizationsDelegate é usado para carregar CustomLocalizations.

• Adicione delegados para MaterialApp, WidgetsApp e CustomLocalization usando propriedades MaterialApp,


localizationsDelegates e SupportedLocales conforme especificado abaixo:

localizaçõesDelegados: [const
CustomLocalizationsDelegate(),
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
],
locais suportados: [ const
Locale('en', ''),

141
Machine Translated by Google

Vibração

const Locale('es', ''),


],

• Use o método CustomLocalizations para obter o valor localizado do título e da mensagem


e use-o em local apropriado conforme especificado abaixo:

class MyHomePage estende StatelessWidget {


MyHomePage({chave-chave, this.title}): super(chave: chave);

título final da String;

@sobrepor
Construção de widget (contexto BuildContext) {
retornar Andaime(
appBar: AppBar(
título: Texto (CustomLocalizations
.of(contexto)
.título),
),
corpo: Centro (
filho: Coluna (
mainAxisAlignment: MainAxisAlignment.center,
filhos: <Widget>[
Texto(
Localizações personalizadas
.of(contexto)
.mensagem,
),
],
),
),
);
}

• Aqui, modificamos a classe MyHomePage de StatefulWidget para StatelessWidget por motivos de


simplicidade e usamos CustomLocalizations para obter o título e a mensagem.

• Compile e execute o aplicativo. O aplicativo mostrará seu conteúdo em inglês.

• Feche o aplicativo. Vá para Configurações -> Sistema -> Idiomas e entrada ->
Línguas*

• Clique em Adicionar uma opção de idioma e selecione Espanhol. Isso instalará o idioma espanhol e o
listará como uma das opções.

• Selecione Espanhol e mova-o acima do Inglês. Isso definirá o espanhol como primeiro idioma e tudo
será alterado para texto em espanhol.

• Agora reinicie o aplicativo de internacionalização e você verá o título e


mensagem em espanhol.

• Podemos reverter o idioma para inglês movendo a opção Inglês acima do espanhol
opção na configuração.

• O resultado da aplicação (em espanhol) é mostrado na imagem abaixo:

142
Machine Translated by Google

Vibração

Usando o pacote intl


Flutter fornece pacote internacional para simplificar ainda mais o desenvolvimento de aplicativos móveis localizados. O pacote intl fornece
métodos e ferramentas especiais para gerar mensagens específicas de idioma de forma semiautomática.

Vamos criar um novo aplicativo localizado usando o pacote intl e entender o conceito.

• Crie um novo aplicativo flutter, flutter_intl_app

• Abra pubspec.yaml e adicione os detalhes do pacote.

dependências:
vibração:
SDK: vibração

flutter_localizations: SDK: flutter

intl: ^0.15.7
intl_translation: ^0.17.3

143
Machine Translated by Google

Vibração

• O Android Studio exibirá o alerta conforme mostrado abaixo informando que o pubspec.yaml
é atualizada.

• Clique na opção Obter dependências. O Android Studio obterá o pacote da Internet e o configurará
adequadamente para o aplicativo.

• Copie o main.dart da amostra anterior, flutter_internationalization_app

• Importe o pacote intl conforme mostrado abaixo:

importar 'pacote:intl/intl.dart';

• Atualize a classe CustomLocalization conforme mostrado no código abaixo:

class CustomLocalizations {
static Future<CustomLocalizations> load(Locale locale) {
final String nome = locale.countryCode.isEmpty? locale.idiomaCode: locale.toString(); string final
localeName =
Intl.canonicalizedLocale(nome);

retornar inicializeMessages(localeName).then((_) {
Intl.defaultLocale = localeName; return
CustomLocalizations(); });

CustomLocalizations estáticos de (contexto BuildContext) {


return Localizations.of<CustomLocalizations>(contexto,
CustomLocalizations);
}

String get title { return


Intl.message( 'Demo',
name:
'title', desc: 'Título
para o aplicativo Demo', );

String receber mensagem{


return Intl.message( 'Hello
World', name:
'message', desc:
'Message for the Demo application', );

}
}

classe CustomLocalizationsDelegate estende


LocalizationsDelegate<CustomLocalizations> { const
CustomLocalizationsDelegate();

@sobrepor

144
Machine Translated by Google

Vibração

bool isSupported(Locale locale) => ['en',


'es'].contains(locale.idiomaCode);

@sobrepor
Future<CustomLocalizations> load(Locale locale) {
retornar CustomLocalizations.load(locale);
}

@sobrepor
bool deveriaReload(CustomLocalizationsDelegate antigo) => falso;
}

• Aqui, usamos três métodos do pacote intl em vez de métodos personalizados.


Caso contrário, os conceitos são os mesmos.

• Intl.canonicalizedLocale - Usado para obter o nome de localidade correto.

• Intl.defaultLocale - Usado para definir a localidade atual.

• Intl.message - Usado para definir novas mensagens.

• importar o arquivo l10n/messages_all.dart . Iremos gerar este arquivo em breve.

importar 'l10n/messages_all.dart';

• Agora, crie uma pasta, lib/l10n

• Abra um prompt de comando e vá para o diretório raiz do aplicativo (onde pubspec.yaml


está disponível) e execute o seguinte comando:

pacotes flutter pub run intl_translation:extract_to_arb --output-dir=lib/l10n lib/main.dart

• Aqui, o comando irá gerar, arquivo intl_message.arb, um modelo para criar mensagem em localidade diferente. O
conteúdo do arquivo é o seguinte:

{
"@@last_modified": "2019-04-19T02:04:09.627551",
"título": "Demonstração",
"@título": {
"description": "Título da aplicação Demo",
"tipo": "texto",
"espaços reservados": {}
},
"mensagem": "Olá mundo",
"@mensagem": {
"description": "Mensagem para a aplicação Demo",
"tipo": "texto",
"espaços reservados": {}
}
}

• Copie intl_message.arb e crie um novo arquivo, intl_en.arb

• Copie intl_message.arb e crie um novo arquivo, intl_es.arb e altere o conteúdo para o idioma espanhol conforme
mostrado abaixo:

145
Machine Translated by Google

Vibração

{
"@@last_modified": "2019-04-19T02:04:09.627551", "title":
"Manifestação", "@title":
{ "description":
"Título para a aplicação Demo", "type": "text ", "espaços reservados":
{} }, "message": "Olá
Mundo", "@message": {

"description": "Mensagem para o aplicativo Demo", "type": "text",


"placeholders": {}

}
}

• Agora, execute o seguinte comando para criar o arquivo de mensagem final, messages_all.dart

pacotes flutter pub run intl_translation:generate_from_arb --output-dir=lib\l10n --no-use-deferred-


loading lib\main.dart lib\l10n\intl_en.arb lib\l10n\intl_es.arb

• Compile e execute o aplicativo. Funcionará de forma semelhante ao aplicativo acima, flutter_localization_app.

146
Machine Translated by Google

17. Vibração – Teste Vibração

O teste é uma fase muito importante no ciclo de vida de desenvolvimento de uma aplicação. Isso garante que o aplicativo
seja de alta qualidade. O teste requer planejamento e execução cuidadosos. É também a fase mais demorada do
desenvolvimento.

A linguagem Dart e a estrutura Flutter fornecem amplo suporte para o teste automatizado de um aplicativo.

Tipos de teste
Geralmente, três tipos de processos de teste estão disponíveis para testar completamente um aplicativo.
Eles são os seguintes:

Teste de unidade

O teste de unidade é o método mais fácil de testar um aplicativo. Baseia-se em garantir a correção de um trecho de código
(uma função, em geral) ou de um método de uma classe. Porém, não reflete o ambiente real e, posteriormente, é a menor
opção para encontrar os bugs.

Teste de widget

O teste de widget é baseado em garantir a exatidão da criação, renderização e interação do widget com outros widgets
conforme esperado. Ele vai um passo além e fornece um ambiente quase em tempo real para encontrar mais bugs.

Teste de integração

O teste de integração envolve testes de unidade e testes de widget junto com componentes externos do aplicativo, como
banco de dados, serviço da web, etc.. Ele simula ou zomba do ambiente real para encontrar quase todos os bugs, mas é o
processo mais complicado.

Flutter fornece suporte para todos os tipos de testes. Ele fornece suporte amplo e exclusivo para testes de widgets. Neste
capítulo, discutiremos detalhadamente os testes de widgets.

Teste de widget
A estrutura de teste Flutter fornece o método testWidgets para testar widgets. Aceita dois argumentos:

• Descrição de teste

• Código de teste

testWidgets('descrição do teste: encontre um widget', '<código de teste>');

147
Machine Translated by Google

Vibração

Etapas envolvidas
O teste de widget envolve três etapas distintas:

• Renderize o widget no ambiente de teste.

• WidgetTester é a classe fornecida pela estrutura de testes Flutter para construir e renderizar o widget.
O método pumpWidget da classe WidgetTester aceita qualquer widget e o renderiza no ambiente
de teste.

testWidgets('encontra uma instância específica', (testador WidgetTester) async {


aguarde tester.pumpWidget(MaterialApp(
casa: Andaime(
corpo: Texto('Olá'),
),
));
});

• Encontrando o widget que precisamos testar.

• A estrutura Flutter oferece muitas opções para encontrar os widgets renderizados no ambiente de
teste e geralmente são chamados de Finders. Os localizadores usados com mais frequência
são find.text, find.byKey e find.byWidget
• find.text encontra o widget que contém o texto especificado.

find.text('Olá')

• find.byKey encontra o widget por sua chave específica.

find.byKey('home')

• find.byWidget encontre o widget por sua variável de instância

encontrar.byWidget(homeWidget)

• Garantir que o widget funcione conforme o esperado.

• A estrutura Flutter oferece muitas opções para combinar o widget com o widget esperado e
normalmente são chamadas de Matchers. Podemos usar o método expect fornecido pela estrutura
de teste para combinar o widget, que encontramos na segunda etapa, com nosso widget esperado,
escolhendo qualquer um dos matchers. Alguns dos matchers importantes são os seguintes:

• findOneWidget - verifica se um único widget foi encontrado.

expect(find.text('Olá'), findOneWidget);

• findNothing - verifica se nenhum widget foi encontrado.

expect(find.text('Olá Mundo'), encontraNothing);

• findWidgets - verifica se mais de um widget foi encontrado.

148
Machine Translated by Google

Vibração

expect(find.text('Salvar'), findWidgets);

• findNWidgets - verifica se N número de widgets foram encontrados.

esperar(encontrar.text('Salvar'), encontraNWidgets(2));

O código de teste completo é o seguinte:

testWidgets('encontra o widget hello', (WidgetTester tester) async { await


tester.pumpWidget(MaterialApp( home:
Scaffold( body:
Text('Hello'),
),
));

expect(find.text('Olá'), findOneWidget);
});

Aqui, renderizamos um widget MaterialApp com o texto Hello usando o widget Text em seu corpo.
Em seguida, usamos find.text para encontrar o widget e, em seguida, combinamos com ele usando findOneWidget.

Exemplo de trabalho
Vamos criar um aplicativo flutter simples e escrever um teste de widget para entender melhor as etapas
envolvidas e o conceito.

• Crie um novo aplicativo flutter, flutter_test_app no Android Studio.

• Abra widget_test.dart na pasta de teste. Ele tem um exemplo de código de teste conforme fornecido abaixo:

testWidgets('Contador incrementa teste de fumaça', (testador WidgetTester) async {


// Construa nosso aplicativo e acione um frame.
aguarde tester.pumpWidget(MyApp());

// Verifique se nosso contador começa em 0.


expect(find.text('0'), findOneWidget);
expect(find.text('1'), encontraNothing);

// Toque no ícone '+' e acione um quadro. aguarde


tester.tap(find.byIcon(Icons.add)); aguarde
tester.pump();

// Verifique se nosso contador foi incrementado.


expect(find.text('0'), encontraNothing);
esperar(encontrar.text('1'), encontraOneWidget); });

• Aqui, o código de teste oferece as seguintes funcionalidades:

• Renderiza o widget MyApp usando tester.pumpWidget

• Garante que o contador seja inicialmente zero usando findOneWidget e findNothing


combinadores.

149
Machine Translated by Google

Vibração

• Encontra o botão de incremento do contador usando o método find.byIcon.

• Toque no botão de incremento do contador usando o método tester.tap.

• Garante que o contador seja aumentado usando findOneWidget e findNothing


combinadores.

• Vamos tocar novamente no botão de incremento do contador e depois verificar se o contador aumentou para dois.

aguarde tester.tap(find.byIcon(Icons.add));
aguarde tester.pump();

esperar(encontrar.text('2'), encontraOneWidget);

• Clique no menu Executar.

• Clique em testes na opção widget_test.dart. Isso executará o teste e reportará o resultado na janela de resultados.

150
Machine Translated by Google

18. Flutter – Implantação Vibração

Este capítulo explica como implantar o aplicativo Flutter nas plataformas Android e iOS.

Aplicativo Android
• Altere o nome do aplicativo usando a entrada android:label no arquivo de manifesto do Android.
Arquivo de manifesto do aplicativo Android, AndroidManifest.xml está localizado em <app dir>/android/
app/src/main. Ele contém detalhes completos sobre um aplicativo Android.
Podemos definir o nome do aplicativo usando a entrada android:label.

• Altere o ícone do iniciador usando a entrada android:icon no arquivo de manifesto.

• Assine o aplicativo usando a opção padrão conforme necessário

• Habilite Proguard e Ofuscação usando a opção padrão, se necessário.

• Crie um arquivo APK de lançamento executando o comando abaixo:

cd /caminho/para/meu/aplicativo
apk de construção de vibração

• Você pode ver uma saída conforme mostrado abaixo:

Inicializando gradle... 8,6s


Resolvendo dependências... 19,9s
Chamando a transformação do artefato JAR simulável para criar o
arquivo: /Users/.gradle/caches/transforms-1/files-1.1/android.jar/
c30932f130afbf3fd90c131ef9069a0b/android.jar com entrada /Users/
Library/Android/sdk/platforms/android-28/android.jar
Executando a tarefa Gradle 'assembleRelease'...
Executando a tarefa Gradle 'assembleRelease'... Concluído 85,7s
Build/app/outputs/apk/release/app-release.apk (4,8 MB).

• Instale o APK em um dispositivo usando o seguinte comando:

instalação de vibração

• Publique o aplicativo no Google Playstore criando um appbundle e envie-o para o Playstore usando
métodos padrão.

flutter build appbundle

Aplicativo iOS
• Registre o aplicativo iOS no App Store Connect usando o método padrão. Salve o =Bundle ID usado
ao registrar o aplicativo.

• Atualize o nome de exibição na configuração do projeto XCode para definir o nome do aplicativo.

151
Machine Translated by Google

Vibração

• Atualize o identificador do pacote na configuração do projeto XCode para definir o ID do pacote, que
usado na etapa 1.

• Codifique conforme necessário usando o método padrão.

• Adicione um novo ícone de aplicativo conforme necessário usando o método padrão.

• Gere o arquivo IPA usando o seguinte comando:

vibração construir ios

• Agora, você pode ver a seguinte saída:

Construindo com.example.MyApp para dispositivo (ios-release)...


Assinar automaticamente o iOS para implantação de dispositivo usando a equipe de desenvolvimento especificada
no projeto Xcode: Executando o
build do Xcode... 23,5s
......................

• Teste o aplicativo enviando o arquivo IPA do aplicativo para o TestFlight usando o método padrão.

• Por fim, envie o aplicativo para a App Store usando o método padrão.

152
Machine Translated by Google

Vibração
19. Flutter – Ferramentas de Desenvolvimento

Este capítulo explica detalhadamente as ferramentas de desenvolvimento do Flutter. A primeira versão estável do kit de
ferramentas de desenvolvimento multiplataforma foi lançada em 4 de dezembro de 2018, Flutter 1.0.
Bem, o Google está trabalhando continuamente nas melhorias e no fortalecimento da estrutura Flutter com diferentes
ferramentas de desenvolvimento.

Conjuntos de widgets

O Google atualizou os conjuntos de widgets Material e Cupertino para fornecer qualidade perfeita em pixels no design dos
componentes. A próxima versão do flutter 1.2 será projetada para suportar eventos de teclado de desktop e suporte para
passar o mouse.

Desenvolvimento Flutter com Visual Studio Code


O Visual Studio Code oferece suporte ao desenvolvimento flutuante e fornece atalhos abrangentes para um desenvolvimento
rápido e eficiente. Alguns dos principais recursos fornecidos pelo Visual Studio Code para desenvolvimento de flutter estão
listados abaixo:

• Assistente de código - Quando quiser verificar opções, você pode usar Ctrl+Espaço para obter uma
lista de opções de conclusão de código.

• Correção rápida - Ctrl+. é uma ferramenta de correção rápida para ajudar a corrigir o código.

• Atalhos durante a codificação

• Fornece documentação detalhada nos comentários.

• Atalhos de depuração.

• Reinicializações a quente

Dart DevTools
Podemos usar Android Studio ou Visual Studio Code, ou qualquer outro IDE para escrever nosso código e instalar plugins. A
equipe de desenvolvimento do Google está trabalhando em mais uma ferramenta de desenvolvimento chamada Dart DevTools.
É um pacote de programação baseado na web. Suporta plataformas Android e iOS. É baseado na visualização da linha do
tempo para que os desenvolvedores possam analisar facilmente seus aplicativos.

Instale DevTools
Para instalar o DevTools, execute o seguinte comando em seu console:

pacotes flutter pub global ativar devtools

Agora você pode ver a seguinte saída:

Resolvendo dependências...
+ argumentos 1.5.1
+ assíncrono 2.2.0

153
Machine Translated by Google

Vibração

+ código de caracteres
1.1.2 + espelho de código 0.5.3+5.44.0
+ coleção 1.14.11
+ converter 2.1.1 +
ferramentas de desenvolvimento 0.0.16

+ devtools_server 0.0.2 + http


0.12.0+2 + http_parser
3.1.3 + intl 0.15.8

+ js 0.6.1+1 + meta
1.1.7
+ mímica 0.9.6+2
..................
..................

Devtools executáveis instalados.

Devtools 0.0.16 ativados.

Executar servidor

Você pode executar o servidor DevTools usando o seguinte comando:

pacotes flutter pub global run devtools

Agora, você receberá uma resposta semelhante a esta,

Servindo DevTools em http://127.0.0.1:9100

Comece seu aplicativo


Acesse sua aplicação, abra o simulador e execute usando o seguinte comando:

execução de vibração --observatório-port=9200

Agora você está conectado ao DevTools.

Inicie o DevTools no navegador

Agora acesse a url abaixo no navegador, para iniciar o DevTools:

http://localhost:9100/?port=9200

Você receberá uma resposta conforme mostrado abaixo:

154
Machine Translated by Google

Vibração

Flutter SDK
Para atualizar o Flutter SDK, use o seguinte comando:

atualização de vibração

Você pode ver uma saída conforme mostrado abaixo:

Para atualizar pacotes Flutter, use o seguinte comando:

atualização de pacotes flutter

Você pode ver a seguinte resposta,

Executando "atualização de pacotes flutter" em my_app... 7,4s

Inspetor de vibração

Ele é usado para explorar árvores de widgets flutuantes. Para conseguir isso, execute o comando abaixo em
seu console,

155
Machine Translated by Google

Vibração

flutter run --track-widget-creation

Você pode ver uma saída conforme mostrado abaixo:

Iniciando lib/main.dart no iPhone X em modo de depuração...

ÿMontando recursos do Flutter... 3,6s


Compilando, vinculando e assinando... 6,8s
Construção do Xcode 14,2s
concluída. 2.904 ms (!)

Para recarregar as alterações durante a execução, pressione "r". Para reiniciar a quente (e reconstruir o estado),
pressione "R".
Um depurador e criador de perfil do Observatory no iPhone X está disponível em: http://127.0.0.1:50399/

Para uma mensagem de ajuda mais detalhada, pressione "h". Para desconectar, pressione “d”; para sair, pressione "q".

Agora vá para o URL, http://127.0.0.1:50399/ você poderá ver o seguinte resultado:

156
Machine Translated by Google

20. Flutter – Escrevendo aplicativos avançados Vibração

Neste capítulo, aprenderemos como escrever um aplicativo móvel completo, despesas_calculadora. O objetivo da calculadora
de despesas é armazenar nossas informações de despesas. O recurso completo do aplicativo é o seguinte:

• Lista de despesas

• Formulário para inserir novas despesas

• Opção para editar/excluir as despesas existentes


• Despesas totais em qualquer instância.

Vamos programar o aplicativo gastos_calculator usando os recursos avançados do framework Flutter mencionados abaixo.

• Uso avançado de ListView para mostrar a lista de despesas

• Programação de formulário

• Programação de banco de dados SQLite para armazenar nossas despesas

• Gerenciamento de estado do scoped_model para simplificar nossa programação.

Vamos começar a programar a aplicação gas_calculator .

• Crie um novo aplicativo Flutter, despesas_calculator no Android Studio.

• Abra pubspec.yaml e adicione dependências de pacote.

dependências:
vibração:
SDK: vibração

sqflite: ^1.1.0
path_provider: ^0.5.0+1
scoped_model: ^1.0.1 intl:
qualquer

• Observe estes pontos aqui:

• sqflite é usado para programação de banco de dados SQLite. •

path_provider é usado para obter o caminho do aplicativo específico do sistema.

• scoped_model é usado para gerenciamento de estado.

• intl é usado para formatação de data

• O Android Studio exibirá o seguinte alerta de que o pubspec.yaml foi atualizado.

• Clique na opção Obter dependências. O Android Studio obterá o pacote da Internet e o configurará adequadamente
para o aplicativo.

157
Machine Translated by Google

Vibração

• Remova o código existente em main.dart

• Adicione novo arquivo, Expense.dart para criar a classe Expense. A classe de despesas terá as propriedades e
métodos abaixo.

• propriedade: id - ID exclusivo para representar um lançamento de despesa no banco de dados SQLite.

• propriedade: quantidade - Valor gasto.

• propriedade: data - Data em que o valor foi gasto.

• imóvel: categoria - Categoria representa a área em que o valor é gasto.

por exemplo, alimentação, viagens, etc.,

• formattedDate - Usado para formatar a propriedade de data

• fromMap - Usado para mapear o campo da tabela do banco de dados para a propriedade no

objeto de despesa e para criar um novo objeto de despesa

fábrica Expense.fromMap(Map<String, dynamic> data) { return


Expense( dados['id'],

dados['quantidade'],
DateTime.parse(dados['data']),
dados['categoria']
);
}

• toMap - Usado para converter o objeto de despesa em Dart Map, que pode ser usado posteriormente
na programação de banco de dados

Mapa<String, dinâmico> toMap() => {


"id": id,
"quantia": quantidade,
"data": data.toString(), "categoria":
categoria, };

• colunas - Variável estática usada para representar o campo do banco de dados.

• Insira e salve o código a seguir no arquivo Expense.dart.

importar 'pacote:intl/intl.dart';

classe Despesa
{ final int id; valor
final duplo; data final
DateTime; categoria String
final;

String get formattedDate { var


formatador = new DateFormat('aaaa-MM-dd'); retornar
formatador.formato(esta.data);
}

colunas finais estáticas = ['id', 'quantia', 'data', 'categoria'];

158
Machine Translated by Google

Vibração

Despesa(este.id, este.valor, esta.data, esta.categoria);

fábrica Expense.fromMap(Map<String, dinâmico> dados) { return


Expense( dados['id'],

dados['quantidade'],
DateTime.parse(dados['data']),
dados['categoria'] );

Mapa<String, dinâmico> toMap() => {


"id": id,
"quantia": quantidade,
"data": data.toString(), "categoria":
categoria, };

• O código acima é simples e autoexplicativo.

• Adicione novo arquivo, Database.dart para criar a classe SQLiteDbProvider. O objetivo da classe SQLiteDbProvider
é o seguinte:

• Obtenha todas as despesas disponíveis no banco de dados usando o método getAllExpenses. Isto
será usado para listar todas as informações de despesas do usuário.

Future<Lista<Despesas>> getAllExpenses() async {


banco de dados final = aguarda banco de dados;

List<Map> results = await db.query("Despesa", colunas: Expense.columns,


orderBy: "data DESC");

List<Despesas> despesas = new List();


results.forEach((resultado) { Despesa
despesa = Expense.fromMap(resultado);
despesas.add(despesa); });

despesas de devolução;
}

• Obtenha informações de despesas específicas com base na identidade de despesas disponível no banco
de dados usando o método getExpenseById. Ele será usado para mostrar informações de despesas
específicas ao usuário.

Future<Despesa> getExpenseById(int id) async {


banco de dados final = aguarda banco de dados;

var resultado = aguarda db.query("Despesa", onde: "id = ", ondeArgs: [id]);

159
Machine Translated by Google

Vibração

retornar resultado.isNotEmpty? Expense.fromMap (resultado. primeiro): Nulo;


}

• Obtenha as despesas totais do usuário usando o método getTotalExpense. Será


usado para mostrar a despesa total atual para o usuário.

Futuro<duplo> getTotalExpense() assíncrono {


banco de dados final = aguarda banco de dados;

List<Mapa> list = await db.rawQuery("Selecione SUM(quantidade) como valor


da despesa");

retornar lista.isNotEmpty? lista[0]["quantidade"] : Nulo;


}

• Adicione novas informações de despesas ao banco de dados usando o método insert. Ele vai
ser usado para adicionar novas entradas de despesas no aplicativo pelo usuário.

Future<Despesa> insert(Despesa de despesa) async {


banco de dados final = aguarda banco de dados;

var maxIdResult = aguarda db.rawQuery("SELECT MAX(id)+1 como


last_inserted_id FROM Expense");
var id = maxIdResult.first["last_inserted_id"];

var resultado = aguardar db.rawInsert(


"INSERIR na despesa (id, valor, data, categoria)"
"
VALORES (?, ?, ?, ?)",
[id, despesa.quantia, despesa.data.toString(), despesa.categoria]

);

retornar Despesa (id, despesa.valor, despesa.data,


despesa.categoria);
}

• Atualize as informações de despesas existentes usando o método de atualização. Ele será utilizado
para editar e atualizar o lançamento de despesas existentes disponíveis no sistema pelo usuário.

update(Produto de despesa) async {


banco de dados final = aguarda banco de dados;

var resultado = aguardar db.update("Despesa", produto.toMap(),


onde: "id =?", ondeArgs: [produto.id]);

resultado de retorno;
}

• Exclua informações de despesas existentes usando o método delete. Será utilizado para retirar o
lançamento de despesas existente disponível no sistema pelo usuário.

excluir(int id) assíncrono {


banco de dados final = aguarda banco de dados;

160
Machine Translated by Google

Vibração

db.delete("Despesa", onde: "id =?", whereArgs: [id]);


}

• O código completo da classe SQLiteDbProvider é o seguinte:

importar 'dardo: assíncrono';


importar 'dardo:io';
importar 'pacote:caminho/caminho.dart';

importar 'pacote:path_provider/path_provider.dart'; importar


'pacote:sqflite/sqflite.dart';

importar 'Despesa.dart';

classe SQLiteDbProvider
{ SQLiteDbProvider._();

final estático SQLiteDbProvider db = SQLiteDbProvider._();

Banco de dados estático _banco de dados;

Future<banco de dados> obtém banco de dados


assíncrono { if (_database !=
null) return _database;

_database = aguarda initDB();


retornar _banco de dados;
}

initDB() assíncrono {
DiretóriodocumentsDirectory = aguarda getApplicationDocumentsDirectory(); String caminho =
join(documentsDirectory.path, "ExpenseDB2.db"); return aguarda
openDatabase( caminho, versão:
1,
onOpen: (db)
{}, onCreate: (banco
de dados de banco de dados, versão int) async {

aguarde db.execute("CREATE TABLE Despesa (" "id


INTEGER PRIMARY KEY,"
"quantidade REAL,"
"data TEXTO,"
"categoria TEXTO"
")");

aguarde db.execute
("INSERT INTO Expense ('id', 'quantia', 'data', 'categoria') valores (?, ?, ?, ?)", [1, 1000,
'2019-04-01 10
:00:00', "Comida"]);

/*await db.execute( "INSERIR


NO Produto ('id', 'nome', 'descrição', 'preço',
'imagem') valores (?, ?, ?, ?, ?)",
[2, "Pixel", "Pixel é o telefone com mais recursos de todos os tempos", 800,

161
Machine Translated by Google

Vibração

"pixel.png"]);

aguarde db.execute (
"INSERT INTO Produto ('id', 'nome', 'descrição', 'preço',
'imagem') valores (?, ?, ?, ?, ?)",
[3, "Laptop", "Laptop é a ferramenta de desenvolvimento mais produtiva", 2000,
"laptop.png"]);

aguarde db.execute (
"INSERT INTO Produto ('id', 'nome', 'descrição', 'preço',
'imagem') valores (?, ?, ?, ?, ?)",
[4, "Tablet", "Laptop é a ferramenta de desenvolvimento mais produtiva", 1500,
"tablet.png"]);

aguarde db.execute (
"INSERT INTO Produto ('id', 'nome', 'descrição', 'preço',
'imagem') valores (?, ?, ?, ?, ?)",
[5, "Pendrive", "iPhone é o telefone estilista de todos os tempos", 100,
"pendrive.png"]);

aguarde db.execute (
"INSERT INTO Produto ('id', 'nome', 'descrição', 'preço',
'imagem') valores (?, ?, ?, ?, ?)",
[6, "Floppy Drive", "iPhone é o telefone estilista de todos os tempos", 20,
"floppy.png"]);
*/
});
}

Future<Lista<Despesas>> getAllExpenses() async {


banco de dados final = aguarda banco de dados;

List<Map> results = await db.query("Despesa", colunas: Expense.columns, orderBy: "data


DESC");

List<Despesas> despesas = new List();


resultados.forEach((resultado) {
Despesa despesa = Expense.fromMap(resultado);
despesas.add(despesa);
});

despesas de devolução;
}

Future<Despesa> getExpenseById(int id) async {


banco de dados final = aguarda banco de dados;

var resultado = aguarda db.query("Despesa", onde: "id = ", ondeArgs: [id]);

retornar resultado.isNotEmpty? Expense.fromMap (resultado. primeiro): Nulo;


}

Futuro<duplo> getTotalExpense() assíncrono {


banco de dados final = aguarda banco de dados;

162
Machine Translated by Google

Vibração

List<Mapa> list = await db.rawQuery("Selecione SUM(valor) como valor da despesa");

retornar lista.isNotEmpty? lista[0]["quantidade"] : Nulo;


}

Future<Despesa> insert(Despesa de despesa) async {


banco de dados final = aguarda banco de dados;

var maxIdResult = aguarda db.rawQuery("SELECT MAX(id)+1 como last_inserted_id FROM Expense");

var id = maxIdResult.first["last_inserted_id"];

var resultado = aguardar db.rawInsert(


"INSERIR na despesa (id, valor, data, categoria)"
"
VALORES (?, ?, ?, ?)",
[id, despesa.quantia, despesa.data.toString(), despesa.categoria]
);

retornar Despesa (id, despesa.valor, despesa.data, despesa.categoria);


}

update(Produto de despesa) async {


banco de dados final = aguarda banco de dados;

var resultado = aguardar db.update("Despesa", produto.toMap(),


onde: "id =?", ondeArgs: [produto.id]);

resultado de retorno;
}

excluir(int id) assíncrono {


banco de dados final = aguarda banco de dados;

db.delete("Despesa", onde: "id =?", whereArgs: [id]);


}
}

• Aqui,

• banco de dados é a propriedade para obter o objeto SQLiteDbProvider.


• initDB é um método usado para selecionar e abrir o banco de dados SQLite.

• Crie um novo arquivo, ExpenseListModel.dart para criar ExpenseListModel. O objetivo do modelo é manter na memória
as informações completas dos gastos do usuário e atualizar a interface do usuário da aplicação sempre que houver
alteração de gastos do usuário na memória. É baseado na classe Model do pacote scoped_model. Possui as
seguintes propriedades e métodos:

• _items - lista privada de despesas

• items - getter para _items como UnmodifiableListView<Expense> para evitar alterações inesperadas
ou acidentais na lista.

• totalExpense - getter para despesas totais com base na variável items.

163
Machine Translated by Google

Vibração

double get totalExpense { double


amount = 0,0; for(var i = 0;
i < _items.length; i++) { quantidade = quantidade +
_items[i].quantidade;
}

valor de devolução;
}

• load - Utilizado para carregar as despesas completas do banco de dados e na variável _items. Ele
também chama notifyListeners para atualizar a IU.

void load()
{ Future<List<Despesa>> list = SQLiteDbProvider.db.getAllExpenses();

list.then( (dbItems) { for(var i


= 0; i < dbItems.length; i++) {
_items.add(dbItems[i]); }

notificarListeners(); });

• byId - Usado para obter uma despesa específica da variável _items.

Despesa porId(int id) { for(var


i = 0; i < _items.length; i++) { if(_items[i].id == id) { return
_items[i];

}
}

retornar nulo;
}

• add - Usado para adicionar um novo item de despesa na variável _items, bem como no banco de
dados. Ele também chama notifyListeners para atualizar a IU.

void add(Item de despesa)


{ SQLiteDbProvider.db.insert(item).then((val) {
_items.add(val);

notificarListeners(); });

• add - Usado para adicionar um novo item de despesa na variável _items, bem como no banco de dados.
Ele também chama notifyListeners para atualizar a IU.

void update(Item de despesa) {

bool encontrado = falso;

164
Machine Translated by Google

Vibração

for(var i = 0; i < _items.length; i++) { if(_items[i].id ==


item.id) { _items[i] = item; encontrado =
verdadeiro;

SQLiteDbProvider.db.update(item); quebrar;

}
}

if(encontrado) notifyListeners();
}

• delete - Usado para remover um item de despesa existente na variável _items, bem como
do banco de dados. Ele também chama notifyListeners para atualizar a IU.

void delete(Item de despesa) {

bool encontrado = falso;

for(var i = 0; i < _items.length; i++) { if(_items[i].id ==


item.id) { encontrado = verdadeiro;

SQLiteDbProvider.db.delete(item.id);
_items.removeAt(i);
quebrar;
}
}

if(encontrado) notifyListeners();
}

• O código completo da classe ExpenseListModel é o seguinte:

importar 'dardo:coleção'; importar


'pacote:scoped_model/scoped_model.dart'; importar 'Despesa.dart';
importar 'Banco de dados.dart';

class ExpenseListModel estende o modelo {

ExpenseListModel() { this.load(); }

lista final<Despesa> _items = [];

UnmodifiableListView<Despesa> obter itens =>


ListView não modificável(_items);

/*Futuro<double> get totalExpense { return


SQLiteDbProvider.db.getTotalExpense(); }*/

double get totalExpense { double


amount = 0,0;

165
Machine Translated by Google

Vibração

for(var i = 0; i < _items.length; i++) { quantidade =


quantidade + _items[i].quantidade;
}

valor de devolução;
}

void load()
{ Future<List<Despesa>> list =
SQLiteDbProvider.db.getAllExpenses();

list.then( (dbItems) { for(var i


= 0; i < dbItems.length; i++) {
_items.add(dbItems[i]);
}

notificarListeners(); });

Despesa porId(int id) { for(var


i = 0; i < _items.length; i++) { if(_items[i].id == id) { return
_items[i];

}
}

retornar nulo;
}

void add(Item de despesa)


{ SQLiteDbProvider.db.insert(item).then((val) {
_items.add(val);

notificarListeners(); });

void update(Item de despesa) {

bool encontrado = falso;

for(var i = 0; i < _items.length; i++) { if(_items[i].id ==


item.id) { _items[i] = item; encontrado =
verdadeiro;

SQLiteDbProvider.db.update(item); quebrar;

}
}

if(encontrado) notifyListeners();
}

void delete(Item de despesa) {

166
Machine Translated by Google

Vibração

bool encontrado = falso;

for(var i = 0; i < _items.length; i++) { if(_items[i].id ==


item.id) { encontrado = verdadeiro;

SQLiteDbProvider.db.delete(item.id);
_items.removeAt(i);
quebrar;
}
}

if(encontrado) notifyListeners();
}
}

• Abra o arquivo main.dart. Importe as classes conforme especificado abaixo:

importar 'pacote:flutter/material.dart'; importar


'pacote:scoped_model/scoped_model.dart'; importar
'ExpenseListModel.dart';

importar 'Despesa.dart';

• Adicione a função principal e chame runApp passando ScopedModel<ExpenseListModel>


ferramenta.

void main()
{ despesas finais = ExpenseListModel();

runApp(ScopedModel<ExpenseListModel>( modelo:
despesas, filho:
MyApp(), ));

• Aqui,

• o objeto despesas carrega todas as informações de despesas do usuário do banco de dados.


Além disso, quando o aplicativo for aberto pela primeira vez, ele criará o banco de dados
necessário com as tabelas adequadas.

• ScopedModel fornece informações de despesas durante todo o ciclo de vida da aplicação e garante a
manutenção do estado da aplicação em qualquer instância. Isso nos permite usar
StatelessWidget em vez de StatefulWidget.

• Crie um MyApp simples usando o widget MaterialApp.

class MyApp extends StatelessWidget { // Este


widget é a raiz do seu aplicativo. @override Compilação do
widget
(contexto BuildContext) {
return MaterialApp( título:
'Despesa', tema:
ThemeData(

167
Machine Translated by Google

Vibração

primárioSwatch: Colors.blue, ),

home: MyHomePage(título: 'Calculadora de despesas'), );

}
}

• Crie o widget MyHomePage para exibir todas as informações de despesas do usuário junto com as despesas
totais na parte superior. O botão flutuante no canto inferior direito será usado para adicionar novas
despesas.

class MyHomePage estende StatelessWidget


{ MyHomePage({Key key, this.title}): super(key: key);

título final da String;

@override
Widget build (contexto BuildContext) { return
Scaffold( appBar:
AppBar( title:
Text(this.title), ), body:

ScopedModelDescendant<ExpenseListModel>( construtor:
(contexto, filho, despesas) { return ListView.separated(

itemCount: despesas.items == nulo? 1:


despesas.itens.comprimento + 1,
itemBuilder: (contexto, índice) { if (index
== 0) { return
ListTile( title:
" +
Text("Despesas totais:
despesas.totalExpense.toString(), estilo: TextStyle(fontSize: 24,fontWeight:
FontWeight.bold), )

); } else
{ índice = índice - 1;
return Dismissible( chave:
Key(expenses.items[index].id.toString()), onDismissed: (direção)
{
despesas.delete(despesas.items[índice]);

Scaffold.of(context).showSnackBar(SnackBar( content:
Text("Item com id, " +
despesas.items[index].id.toString()
+
"é descartado")));
},
filho: ListTile( onTap: ()

{ Navigator.push( context,

MaterialPageRoute( builder:
(context) => FormPage( id:

despesas.itens[índice].id,

168
Machine Translated by Google

Vibração

despesas: despesas, )));

},
inicial: Icon(Icons.monetization_on), final:

Icon(Icons.keyboard_arrow_right),
título: Texto(despesas.items[índice].categoria
+
":" +

despesas.items[index].amount.toString() + " \nsgasto em


"
+
despesas.items[index].formattedDate, style:
TextStyle(fontSize: 18, fontStyle: FontStyle.italic),))); } }, separatorBuilder: (contexto, índice)

{ return Divider(); }, ); }, ), flutuanteActionButton:

ScopedModelDescendant<ExpenseListModel>( construtor:
(contexto, filho, despesas) { return
FloatingActionButton( onPressed: () {

Navigator.push( contexto,

MaterialPageRoute( construtor:
(contexto) =>
ScopedModelDescendant<ExpenseListModel>(
construtor: (contexto, filho, despesas) { return
FormPage(id: 0,

despesas: despesas, ); }))); //

despesas.add(new Expense( 2, 1000,


DateTime.parse('2019-04-01 11:00:00'), //
'Comida'));
// imprimir(despesas.items.length); }, dica de

ferramenta: 'Increment', filho:


Icon(Icons.add), ); }));

}
}

• Aqui,

• ScopedModelDescendant é usado para passar o modelo de despesas para o ListView e


Widget FloatingActionButton.

169
Machine Translated by Google

Vibração

• O widget ListView.separated e ListTile é usado para listar as informações de despesas.

• O widget dispensável é usado para excluir a entrada de despesas usando o gesto de deslizar.

• O Navigator é usado para abrir a interface de edição de um lançamento de despesas. Pode ser ativado por
tocando em uma entrada de despesas.

• Crie um widget FormPage. A finalidade do widget FormPage é adicionar ou atualizar uma entrada de despesas.
Ele também lida com a validação de entrada de despesas.

classe FormPage estende StatefulWidget {


FormPage({chave-chave, this.id, this.expenses}): super(chave: chave);

ID interno final;
despesas finais de ExpenseListModel;

@sobrepor
_FormPageState createState() => _FormPageState(id: id, despesas: despesas); }

classe _FormPageState estende State<FormPage> {


_FormPageState({Chave-chave, this.id, this.expenses});

ID interno final;
despesas finais de ExpenseListModel;

final scaffoldKey = GlobalKey<ScaffoldState>(); final formKey =


GlobalKey<FormState>();

valor duplo;
DataHora _data;
String _categoria;

void _submit() {
formulário final = formKey.currentState;

if (form.validate()) {form.save();

se (este.id == 0)
despesas.add(Despesa(0, _quantia, _data, _categoria)); senão

despesas.update(Expense(this.id, _amount, _date, _category));

Navigator.pop(contexto);
}
}

@sobrepor
Construção de widget (contexto BuildContext)
{ return Scaffold (
key: scaffoldKey,
appBar: AppBar( title:
Text('Inserir detalhes da despesa'),

170
Machine Translated by Google

Vibração

),
corpo:
Padding( preenchimento: const EdgeInsets.all(16.0), filho:
Form( chave:
formKey, filho:
Column( filhos:

[ TextFormField( estilo:
TextStyle(fontSize: 22), decoração: const
InputDecoration( ícone: const Icon(Icons.monetization_on),
labelText: 'Quantidade', labelStyle: TextStyle(fontSize:

18)),
validador: (val) {
Padrão padrão = r'^[1-9]\d*(\.\d+)?$'; RegExp regex = novo
RegExp(padrão); if (!regex.hasMatch(val)) return 'Digite um
número válido'; outro

retornar nulo;
},
valor inicial:
id == 0? '' : despesas.byId(id).amount.toString(), onSaved: (val) =>
_amount = double.parse(val), ), TextFormField( estilo: TextStyle(fontSize:

22), decoração: const


InputDecoration(

ícone: const Icon (Icons.calendar_today), hintText: 'Inserir data',


labelText: 'Data', labelStyle: TextStyle
(fontSize: 18), ), validador: (val) {

Padrão padrão = r'^((?:19|


20)\d\d)[- /.](0[1-9]|1[012])[- /.](0[1- 9]| [12][0-9]|3[01])$';

RegExp regex = novo RegExp(padrão); se (!


regex.hasMatch(val))
return 'Insira uma data válida'; caso

contrário, retorne nulo;


},
onSaved: (val) => _date = DateTime.parse (val), inicialValue: id == 0 ? ''
despesas.byId(id).formattedDate, :
keyboardType: TextInputType.datetime, ),
TextFormField( estilo: TextStyle(fontSize: 22), decoração:

const
InputDecoration( ícone: const Icon(Icons.category),
labelText:

'Categoria', labelStyle: TextStyle(fontSize: 18)), onSaved: (val) => _category = val,


inicialValue: id == 0 ? ''

: despesas.byId(id).categoria.toString(),

171
Machine Translated by Google

Vibração

),

RaisedButton( onPressed:
_submit, filho: new

Text('Enviar'), ), ], ), ), ), );
}
}

• Aqui,

• TextFormField é usado para criar entrada de formulário.

• a propriedade validator de TextFormField é usada para validar o elemento do formulário junto com
Padrões RegEx.

• A função _submit é usada junto com o objeto de despesas para adicionar ou atualizar as despesas no banco de dados.

• O código completo do arquivo main.dart é o seguinte:

importar 'pacote:flutter/material.dart'; importar


'pacote:scoped_model/scoped_model.dart'; importar 'ExpenseListModel.dart';

importar 'Despesa.dart';

void principal() {
despesas finais = ExpenseListModel();

runApp(ScopedModel<ExpenseListModel>( modelo:
despesas, filho:
MyApp(), ));

class MyApp extends StatelessWidget { // Este widget é


a raiz do seu aplicativo. @override Compilação do widget (contexto
BuildContext)
{
return MaterialApp(título:
'Despesa', tema:
ThemeData(primárioSwatch:
Colors.blue, ), home: MyHomePage(título:

'Calculadora de despesas'), );

}
}

class MyHomePage estende StatelessWidget {

172
Machine Translated by Google

Vibração

MyHomePage({chave-chave, this.title}): super(chave: chave);

título final da String;

@override
Widget build (contexto BuildContext) { return Scaffold( appBar:
AppBar( title:
Text(this.title), ), body:

ScopedModelDescendant<ExpenseListModel>( construtor: (contexto, filho,


despesas) { return ListView.separated(

itemCount: despesas.items == nulo? 1:


despesas.itens.comprimento + 1,
itemBuilder: (contexto, índice) { if (index == 0)
{ return ListTile( title:
Text("Despesas totais:
"
despesas.totalExpense.toString(), estilo: +

TextStyle(fontSize: 24,fontWeight: FontWeight.bold), )

); } else
{ índice = índice - 1; return
Dismissible( chave:
Key(expenses.items[index].id.toString()), onDismissed: (direção) {

despesas.delete(despesas.items[índice]);

Scaffold.of(context).showSnackBar(SnackBar( content: Text("Item com


id, " despesas.items[index].id.toString() + " é +

dispensado")));

},
filho: ListTile( onTap: ()

{ Navigator.push( context,

MaterialPageRoute( construtor:
(context) => FormPage(
id: despesas.items[index].id,
despesas: despesas, )));

},
inicial: Icon(Icons.monetization_on), final:
Icon(Icons.keyboard_arrow_right), título: Text(expenses.items[index].category
+
": " +

despesas.items[index].amount.toString() + " \nsgasto em


"
+

despesas.items[index].formattedDate, estilo:
TextStyle(fontSize: 18, fontStyle: FontStyle.italic),)));

} }, separatorBuilder: (contexto, índice) {

173
Machine Translated by Google

Vibração

return Divisor(); }, ); }, ),

floatActionButton: ScopedModelDescendant<ExpenseListModel>( construtor: (contexto,


filho, despesas) { return FloatingActionButton( onPressed:
() {

Navigator.push
(contexto,
MaterialPageRoute
(construtor: (contexto) =>
ScopedModelDescendant<ExpenseListModel>( construtor:
(contexto, filho, despesas) { return FormPage( id: 0,

despesas: despesas, ); }))); //

despesas.add(nova Despesa( // 2, 1000,


DateTime.parse('2019-04-01 11:00:00'),
'Comida'));
// imprimir(despesas.items.length); }, dica de

ferramenta: 'Increment', filho:


Icon(Icons.add), ); }));

}
}

classe FormPage estende StatefulWidget {


FormPage({chave-chave, this.id, this.expenses}): super(chave: chave);

ID interno final;
despesas finais de ExpenseListModel;

@sobrepor
_FormPageState createState() => _FormPageState(id: id, despesas: despesas); }

classe _FormPageState estende State<FormPage> {


_FormPageState({Chave-chave, this.id, this.expenses});

ID interno final;
despesas finais de ExpenseListModel;

final scaffoldKey = GlobalKey<ScaffoldState>(); final formKey =


GlobalKey<FormState>();

valor duplo;
DataHora _data;
String _categoria;

174
Machine Translated by Google

Vibração

void _submit() {
formulário final = formKey.currentState;

if (form.validate()) {form.save();

se (este.id == 0)
despesas.add(Despesa(0, _quantia, _data, _categoria)); senão

despesas.update(Expense(this.id, _amount, _date, _category));

Navigator.pop(contexto);
}
}

@sobrepor
Construção de widget (contexto BuildContext) { return
Scaffold (
key: scaffoldKey, appBar:
AppBar( title: Text('Inserir
detalhes da despesa'), ), body: Padding( padding: const

EdgeInsets.all(16.0),
child: Form( key: formKey, child: Column( children:

[ TextFormField( estilo:
TextStyle(fontSize:
22), decoração:
const
InputDecoration( ícone: const
Icon(Icons.monetization_on), labelText: 'Quantidade',
labelStyle: TextStyle(fontSize:

18)),
validador: (val) {
Padrão padrão = r'^[1-9]\d*(\.\d+)?$'; RegExp regex = novo
RegExp(padrão); if (!regex.hasMatch(val)) return 'Digite um
número válido'; outro

retornar nulo;
},
valor inicial:
id == 0? '' : despesas.byId(id).amount.toString(), onSaved: (val) =>
_amount = double.parse(val), ), TextFormField( estilo: TextStyle(fontSize:

22), decoração: const


InputDecoration(

ícone: const Icon (Icons.calendar_today), hintText: 'Inserir


data', labelText: 'Data', labelStyle:
TextStyle (fontSize: 18), ), validador: (val) {

175
Machine Translated by Google

Vibração

Padrão padrão = r'^((?:19|


20)\d\d)[- /.](0[1-9]|1[012])[- /.](0[1- 9]| [12][0-9]|3[01])$';

RegExp regex = novo RegExp(padrão); se (!


regex.hasMatch(val))
return 'Insira uma data válida'; caso

contrário, retorne nulo;


},
onSaved: (val) => _date = DateTime.parse (val), inicialValue: id == 0 ? ''
despesas.byId(id).formattedDate, :
keyboardType: TextInputType.datetime, ),
TextFormField( estilo: TextStyle(fontSize: 22), decoração:

const
InputDecoration( ícone: const Icon(Icons.category),
labelText:

'Categoria', labelStyle: TextStyle(fontSize: 18)), onSaved: (val) => _category =


val, inicialValue: id == 0 ? ''

: despesas.byId(id).categoria.toString(),
),

RaisedButton( onPressed:
_submit, filho: new

Text('Enviar'), ), ], ), ), ), );
}
}

• Agora, execute o aplicativo.

• Adicione novas despesas usando o botão flutuante.

• Edite as despesas existentes tocando na entrada de despesas

• Exclua as despesas existentes deslizando a entrada de despesas em qualquer direção.

176
Machine Translated by Google

Vibração

Algumas das capturas de tela do aplicativo são as seguintes:

177
Machine Translated by Google

Vibração

178
Machine Translated by Google

Vibração

179
Machine Translated by Google

21. Vibração – Conclusão Vibração

A estrutura Flutter faz um ótimo trabalho ao fornecer uma excelente estrutura para construir aplicativos móveis de uma forma
verdadeiramente independente de plataforma. Ao fornecer simplicidade no processo de desenvolvimento, alto desempenho
no aplicativo móvel resultante, interface de usuário rica e relevante para plataformas Android e iOS, a estrutura Flutter
certamente permitirá que muitos novos desenvolvedores desenvolvam aplicativos móveis de alto desempenho e cheios de
recursos no futuro próximo.

180

Você também pode gostar