Flutter - Guia rápido

Em geral, desenvolver um aplicativo móvel é uma tarefa complexa e desafiadora. Existem muitas estruturas 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 / Swift.

No entanto, para desenvolver um aplicativo que suporte os dois sistemas operacionais, precisamos codificar em duas linguagens diferentes, usando duas estruturas diferentes. Para ajudar a superar essa complexidade, existem estruturas móveis que suportam ambos os sistemas operacionais. Essas estruturas variam de estrutura de aplicativo móvel híbrido baseado em HTML simples (que usa HTML para interface de usuário e JavaScript para lógica de aplicativo) a estrutura de linguagem específica (que faz o trabalho pesado de converter código em código nativo). Independentemente de sua simplicidade ou complexidade, esses frameworks sempre apresentam muitas desvantagens, sendo uma das principais desvantagens seu desempenho lento.

Neste cenário, Flutter - uma estrutura simples e de alto desempenho baseada na linguagem Dart, fornece alto desempenho ao renderizar a IU diretamente na tela do sistema operacional, em vez de por meio da estrutura nativa.

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

Para ser mais específico, o aplicativo Flutter é em si um widget. Os widgets Flutter também oferecem suporte a 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á comparar automaticamente (programação reativa) o estado do widget (antigo e novo) e renderizar o widget apenas com as alterações necessárias, em vez de renderizar novamente todo o widget.

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

Características do Flutter

A estrutura Flutter oferece os seguintes recursos para 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 IU para várias plataformas.

  • Aplicativo de alto desempenho.

Vantagens do Flutter

Flutter vem com widgets bonitos e personalizáveis ​​para alto desempenho e aplicativos móveis excelentes. Ele atende a todas as necessidades e requisitos personalizados. Além disso, o Flutter oferece muito mais vantagens, conforme mencionado abaixo -

  • O Dart possui um grande repositório de pacotes de software que permite estender os recursos de seu aplicativo.

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

  • Flutter precisa de menos testes. Por causa de sua base de código única, é suficiente se escrevermos 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.

  • O Flutter oferece ótimas ferramentas de desenvolvedor, com uma incrível recarga a quente.

Desvantagens da flutuação

Apesar de suas muitas vantagens, a vibração tem as seguintes desvantagens -

  • Uma vez que é 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 IU 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 altamente populado.

Este capítulo irá guiá-lo através da instalação do Flutter em seu computador local em detalhes.

Instalação em Windows

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

Step 1 - Vá para URL,https://flutter.dev/docs/get-started/install/windowse 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.

Step 2 - Descompacte o arquivo zip em uma pasta, diga C: \ flutter \

Step 3 - Atualize o caminho do sistema para incluir o diretório bin flutter.

Step 4 - Flutter fornece uma ferramenta, médico de vibração para verificar se todos os requisitos de desenvolvimento de vibração são atendidos.

flutter doctor

Step 5 - Executar o comando acima irá analisar o sistema e mostrar seu relatório conforme mostrado abaixo -

Doctor summary (to see all details, run flutter doctor -v):
[√] Flutter (Channel stable, v1.2.1, on Microsoft Windows [Version
10.0.17134.706], locale en-US)
[√] Android toolchain - develop for Android devices (Android SDK version
28.0.3)
[√] Android Studio (version 3.2)
[√] VS Code, 64-bit edition (version 1.29.1)
[!] Connected device
! No devices available
! Doctor found issues in 1 category.

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

Step 6 - Instale o SDK do Android mais recente, se relatado pelo médico de flutter

Step 7 - Instale o Android Studio mais recente, se relatado pelo médico de vibração

Step 8 - Inicie um emulador de Android ou conecte um dispositivo Android real ao sistema.

Step 9- Instale o plugin Flutter and 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 estúdio Android, etc.,

  • 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 plug-in Dart.

  • Reinicie o Android Studio.

Instalação em MacOS

Para instalar o Flutter no MacOS, você terá que seguir os seguintes passos -

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

Step 2 - Descompacte o arquivo zip em uma pasta, diga / path / to / flutter

Step 3 - Atualize o caminho do sistema para incluir o diretório bin flutter (no arquivo ~ / .bashrc).

> export PATH = "$PATH:/path/to/flutter/bin"

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

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

Flutter fornece uma ferramenta, médico de vibração para verificar se todos os requisitos de desenvolvimento de vibração são atendidos. É semelhante à contraparte do Windows.

Step 5 - Instale o XCode mais recente, se relatado pelo médico de flutter

Step 6 - Instale o SDK do Android mais recente, se relatado pelo médico de flutter

Step 7 - Instale o Android Studio mais recente, se relatado pelo médico de vibração

Step 8 - Inicie um emulador de Android ou conecte um dispositivo Android real ao sistema para desenvolver o aplicativo Android.

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

Step 10- Instale o plugin Flutter and 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 Preferences → Plugins

  • Selecione o plugin Flutter e clique em Instalar

  • Clique em Sim quando solicitado a instalar o plug-in Dart.

  • Reinicie o 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.

Step 1 - Abra o Android Studio

Step 2- Criar projeto Flutter. Para isso, cliqueFile → New → New Flutter Project

Step 3- Selecione o aplicativo Flutter. Para isso, selecioneFlutter Application e clique Next.

Step 4 - Configure o aplicativo conforme abaixo e clique em Next.

  • Nome do Projeto: hello_app

  • Caminho do Flutter SDK: <path_to_flutter_sdk>

  • Localização do projeto: <path_to_project_folder>

  • Descrição: Flutter based hello world application

Step 5 - Configurar projeto.

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

Step 6 - Insira o domínio da empresa.

O Android Studio cria um aplicativo de flutter totalmente funcional com funcionalidade mínima. Vamos verificar a estrutura do aplicativo e, em seguida, alterar o código para fazer nossa tarefa.

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 aplicativos Android

  • ios - Código-fonte gerado automaticamente para criar aplicativos ios

  • lib - Pasta principal contendo código Dart escrito usando estrutura flutter

  • ib/main.dart - Ponto de entrada do aplicativo Flutter

  • test - Pasta contendo o código Dart para testar o aplicativo flutter

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

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

  • .metadata - gerado automaticamente pelas ferramentas de vibração

  • .packages - gerado automaticamente para rastrear os pacotes de vibração

  • .iml - arquivo de projeto usado pelo Android Studio

  • pubspec.yaml - Usado por Pub, Gerenciador de pacotes Flutter

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

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

Step 7- Substitua o código do dart no arquivo lib / main.dart pelo código abaixo -

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
   // This widget is the root of your application.
   @override
   Widget build(BuildContext context) {
      return MaterialApp(
         title: 'Hello World Demo Application',
         theme: ThemeData(
            primarySwatch: Colors.blue,
         ),
         home: MyHomePage(title: 'Home page'),
      );
   }
}
class MyHomePage extends StatelessWidget {
   MyHomePage({Key key, this.title}) : super(key: key);
   final String title;

   @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.

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

  • Line 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.

  • Line 5-17- Widget é usado para criar UI em estrutura de 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 objetivo do método de construção é criar uma parte da IU do aplicativo. Aqui, o método de construção usa MaterialApp , um widget para criar a UI de nível raiz do aplicativo. Possui três propriedades - título, tema e casa .

    • título é o título do aplicativo

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

    • home é a interface do usuário interna do aplicativo, que definimos outro widget, MyHomePage

  • Line 19 - 38- MyHomePage é o mesmo que MyApp, exceto que retorna o widget Scaffold . Scaffold é um widget de nível superior ao lado do widget MaterialApp usado para criar design de material em conformidade com a IU. Ele tem duas propriedades importantes, appBar para mostrar o cabeçalho do aplicativo e corpo para mostrar o conteúdo real do aplicativo. AppBar é outro widget para renderizar o cabeçalho do aplicativo e nós o usamos na propriedade appBar . Na propriedade body , usamos o widget Center , que centraliza o widget filho. Texto é o widget final e interno para mostrar o texto e é exibido no centro da tela.

Step 8 - Agora, execute o aplicativo usando, Run → Run main.dart

Step 9 - Por fim, a saída do aplicativo é a seguinte -

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

Widgets

O conceito central da estrutura Flutter é In Flutter, Everything is a widget. Widgets são basicamente componentes da interface do usuário usados ​​para criar a interface do usuário do aplicativo.

No Flutter , o próprio aplicativo é um widget. O aplicativo é o widget de nível superior e sua IU é construída usando um ou mais filhos (widgets), que novamente são construídos usando seus widgets filhos. estecomposability recurso nos ajuda a criar uma interface de usuário de qualquer complexidade.

Por exemplo, a hierarquia do widget do aplicativo hello world (criado no capítulo anterior) é conforme especificado no diagrama a seguir -

Aqui, os seguintes pontos são dignos de nota -

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

  • MaterialApp tem 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 de vibração, Scaffold

  • Scaffold tem duas propriedades - body e appBar

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

  • Header UI é construída usando widget nativo de vibração, AppBar e Body UI são construídas usando widget Center .

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

Gestos

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

Conceito de Estado

Widgets Flutter suportam manutenção de estado fornecendo um widget especial, StatefulWidget . O widget precisa ser derivado do widget StatefulWidget para suportar a manutenção do estado e todos os outros widgets devem ser derivados do StatefulWidget . Widgets Flutter sãoreactiveem nativo. Isso é semelhante a reactjs e StatefulWidget será renderizado automaticamente sempre que seu estado interno for alterado. A re-renderização é otimizada encontrando a diferença entre a interface de usuário do widget antigo e novo e renderizando apenas as mudanças necessárias

Camadas

O conceito mais importante da estrutura Flutter é que a estrutura é agrupada em várias categorias em termos de complexidade e claramente organizada em camadas de complexidade decrescente. Uma camada é construída usando sua camada de próximo nível imediata. A camada superior é um widget específico para Android e iOS . A próxima camada tem 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 para o código específico da plataforma principal

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 de widgets já existentes.

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

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

  • O 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.

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

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

void main() {
   print("Dart language is easy to learn");
}

Variáveis ​​e tipos de dados

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

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

var name = 'Dart';

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

void main() {
   final a = 12;
   const pi = 3.14;
   print(a);
   print(pi);
}

A linguagem Dart suporta os seguintes tipos de dados -

  • Numbers - É usado para representar literais numéricos - Inteiro e Duplo.

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

  • Booleans- O Dart usa a palavra-chave bool para representar os valores booleanos - verdadeiro e falso.

  • Lists and Maps- É usado para representar uma coleção de objetos. Uma lista simples pode ser definida como abaixo -.

void main() {
   var list = [1,2,3,4,5];
   print(list);
}

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

O mapa pode ser definido como mostrado aqui -

void main() {
   var mapping = {'id': 1,'name':'Dart'};
   print(mapping);
}
  • Dynamic- Se o tipo de variável não for definido, seu tipo padrão é dinâmico. O exemplo a seguir ilustra a variável de tipo dinâmico -

void main() {
   dynamic name = "Dart";
   print(name);
}

Tomada de decisão e loops

Um bloco de tomada de decisão avalia uma condição antes que as instruções sejam executadas. O Dart é compatível com as instruções If, If..else e switch.

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

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) {
         print(i);
      }
   }
}

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. Vejamos 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;
   print(c);
}

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 oferece suporte a recursos de programação orientada a objetos, como classes, interfaces, etc.

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

  • Fields
  • Getters e setters
  • Constructors
  • Functions

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

class Employee {
   String name;
   
   //getter method
   String get emp_name {
      return name;
   }
   //setter method
   void set emp_name(String name) {
      this.name = name;
   }
   //function definition
   void result() {
      print(name);
   }
}
void main() {
   //object creation
   Employee emp = new Employee();
   emp.name = "employee1";
   emp.result(); //function call
}

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 este propósito é fornecido abaixo -

class MyHomePage extends StatelessWidget { 
   MyHomePage({Key key, this.title}) : super(key: key); 
   
   final String title; 
   @override 
   Widget build(BuildContext context) {
      return Scaffold( 
         appBar: AppBar(title: Text(this.title), ), 
         body: Center(child: Text( 'Hello World',)),
      );
   }
}

Aqui, criamos um novo widget estendendo StatelessWidget .

Observe que o StatelessWidget requer apenas um único método de construção a ser implementado em sua classe derivada. O método build obtém o ambiente de contexto necessário para construir os widgets por meio 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 de Scaffold , que por sua vez chama o método build 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 .

Para um melhor entendimento, a representação visual do mesmo é dada 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 de plataforma
  • Widgets de layout
  • Widgets de manutenção de estado
  • Widgets independentes / básicos de plataforma

Vamos discutir cada um deles em detalhes agora.

Widgets específicos de plataforma

Flutter tem widgets específicos para uma plataforma particular - Android ou iOS.

Widgets específicos para Android são projetados de acordo com as diretrizes de design de materiais do sistema operacional Android. Os 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 Cupertino .

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

  • Scaffold
  • AppBar
  • BottomNavigationBar
  • TabBar
  • TabBarView
  • ListTile
  • RaisedButton
  • FloatingActionButton
  • FlatButton
  • IconButton
  • DropdownButton
  • PopupMenuButton
  • ButtonBar
  • TextField
  • Checkbox
  • Radio
  • Switch
  • Slider
  • Selecionadores de data e hora
  • SimpleDialog
  • AlertDialog

Alguns dos widgets Cupertino mais usados são os seguintes -

  • CupertinoButton
  • CupertinoPicker
  • CupertinoDatePicker
  • CupertinoTimerPicker
  • CupertinoNavigationBar
  • CupertinoTabBar
  • CupertinoTabScaffold
  • CupertinoTabView
  • CupertinoTextField
  • CupertinoDialog
  • CupertinoDialogAction
  • CupertinoFullscreenDialogTransition
  • CupertinoPageScaffold
  • CupertinoPageTransition
  • CupertinoActionSheet
  • CupertinoActivityIndicator
  • CupertinoAlertDialog
  • CupertinoPopupSurface
  • CupertinoSlider

Widgets de layout

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

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

  • Container- Uma caixa retangular decorada com widgets BoxDecoration com fundo, borda e sombra.

  • Center - Centralize seu widget filho.

  • Row - Organize seus filhos na direção horizontal.

  • Column - Organize seus filhos na direção vertical.

  • Stack - Organize um acima do outro.

Verificaremos os widgets de layout em detalhes no próximo capítulo de introdução aos widgets de layout .

Widgets de manutenção de estado

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

Widget derivado de StatelessWidget não tem nenhuma informação de estado, mas pode conter widget derivado de StatefulWidget . A natureza dinâmica do aplicativo é através do comportamento interativo dos widgets e as 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 de gerenciamento de estado .

Widgets independentes / básicos de plataforma

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

Text

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 amostra para esta finalidade é o seguinte -

Text('Hello World!', style: TextStyle(fontWeight: FontWeight.bold))

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

Text.rich( 
   TextSpan( 
      children: <TextSpan>[ 
         TextSpan(text: "Hello ", style:  
         TextStyle(fontStyle: FontStyle.italic)),  
         TextSpan(text: "World", style: 
         TextStyle(fontWeight: FontWeight.bold)),  
      ], 
   ), 
)

As propriedades mais importantes do widget de texto são as seguintes -

  • maxLines, int - Número máximo de linhas para mostrar

  • overflow, TextOverFlow- Especifique como o estouro visual é tratado usando a classe TextOverFlow

  • style, TextStyle- Especifique o estilo da string usando a classe TextStyle

  • textAlign, TextAlign- Alinhamento do texto como direita, esquerda, justificar, etc., usando a classe TextAlign

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

Image

O widget de imagem é usado para exibir uma imagem no aplicativo. O widget de imagem fornece diferentes construtores para carregar imagens de várias fontes e são as seguintes -

  • Image- Carregador de imagem genérico usando ImageProvider

  • Image.asset - Carregar imagem de ativos de projeto de flutter

  • Image.file - Carregar imagem da pasta do sistema

  • Image.memory - Carregar imagem da memória

  • Image.Network - Carregar 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 -

flutter: 
   assets: 
      - assets/smiley.png
  • Agora, carregue e exiba a imagem no aplicativo.

Image.asset('assets/smiley.png')
  • O código-fonte completo do widget MyHomePage do aplicativo hello world e o resultado é mostrado abaixo -.

class MyHomePage extends StatelessWidget {
   MyHomePage({Key key, this.title}) : super(key: key); 
   final String title; 

   @override 
   Widget build(BuildContext context) {
      return Scaffold( 
         appBar: AppBar( title: Text(this.title), ), 
         body: Center( child: Image.asset("assets/smiley.png")),
      ); 
   }
}

A imagem carregada é como mostrado abaixo -

Maioria das propriedades importantes da Imagem Widget são os seguintes -

  • image, ImageProvider - Imagem real para carregar

  • width, double - Largura da imagem

  • height, double - Altura da imagem

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

Icon

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 -

Icon(Icons.email)

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

class MyHomePage extends StatelessWidget { 
   MyHomePage({Key key, this.title}) : super(key: key); 
   final String title; 

   @override 
   Widget build(BuildContext context) {
      return Scaffold(
         appBar: AppBar(title: Text(this.title),),
         body: Center( child: Icon(Icons.email)),
      );
   }
}

O ícone carregado é mostrado abaixo -

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

Tipo de Layout Widgets

Os widgets de layout podem ser agrupados em duas categorias distintas com base em seu filho -

  • Widget apoiando uma única criança
  • Widget que suporta vários filhos

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

Widgets de filho único

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 opções diferentes 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, etiqueta, etc.,

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

class MyButton extends StatelessWidget {
   MyButton({Key key}) : super(key: key); 

   @override 
   Widget build(BuildContext context) {
      return Container(
         decoration: const BoxDecoration(
            border: Border(
               top: BorderSide(width: 1.0, color: Color(0xFFFFFFFFFF)),
               left: BorderSide(width: 1.0, color: Color(0xFFFFFFFFFF)),
               right: BorderSide(width: 1.0, color: Color(0xFFFF000000)),
               bottom: BorderSide(width: 1.0, color: Color(0xFFFF000000)),
            ),
         ),
         child: Container(
            padding: const
            EdgeInsets.symmetric(horizontal: 20.0, vertical: 2.0),
            decoration: const BoxDecoration(
               border: Border(
                  top: BorderSide(width: 1.0, color: Color(0xFFFFDFDFDF)),
                  left: BorderSide(width: 1.0, color: Color(0xFFFFDFDFDF)),
                  right: BorderSide(width: 1.0, color: Color(0xFFFF7F7F7F)),
                  bottom: BorderSide(width: 1.0, color: Color(0xFFFF7F7F7F)),
               ),
               color: Colors.grey,
            ),
            child: const Text(
               'OK',textAlign: TextAlign.center, style: TextStyle(color: Colors.black)
            ), 
         ), 
      ); 
   }
}

Aqui, usamos dois widgets - um widget de contêiner e um widget de texto . 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 -

  • Padding- Usado para organizar seu widget filho pelo preenchimento fornecido. Aqui, o preenchimento pode ser fornecido pela classe EdgeInsets .

  • Align- Alinhe seu widget filho dentro dele 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 a parte inferior esquerda.

Um exemplo de código sobre offsets é mostrado abaixo -

Center(
   child: Container(
      height: 100.0, 
      width: 100.0, 
      color: Colors.yellow, child: Align(
         alignment: FractionalOffset(0.2, 0.6),
         child: Container( height: 40.0, width:
            40.0, color: Colors.red,
         ), 
      ), 
   ), 
)
  • FittedBox - Ele dimensiona o widget filho e o posiciona de acordo com o ajuste especificado.

  • AspectRatio - Tenta dimensionar o widget filho para a proporção especificada

  • ConstrainedBox

  • Baseline

  • FractinallySizedBox

  • IntrinsicHeight

  • IntrinsicWidth

  • LiimitedBox

  • OffStage

  • OverflowBox

  • SizedBox

  • SizedOverflowBox

  • Transform

  • CustomSingleChildLayout

Nosso aplicativo hello world está usando widgets de layout baseados em material 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 -

  • Container - Widget de contêiner genérico, filho único, baseado em caixa com alinhamento, preenchimento, borda e margem junto com recursos de estilo ricos.

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

O código modificado do widget MyHomePage e MyApp é como abaixo -

class MyApp extends StatelessWidget {
   @override
   Widget build(BuildContext context) {
      return MyHomePage(title: "Hello World demo app");
   }
}
class MyHomePage extends StatelessWidget {
   MyHomePage({Key key, this.title}) : super(key: key);
   final String title;
   @override
   Widget build(BuildContext context) {
      return Container(
         decoration: BoxDecoration(color: Colors.white,),
         padding: EdgeInsets.all(25), child: Center(
            child:Text(
               'Hello World', style: TextStyle(
                  color: Colors.black, letterSpacing: 0.5, fontSize: 20,
               ),
               textDirection: TextDirection.ltr,
            ),
         )
      );
   }
}

Aqui,

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

  • BoxDecoration tem muitas propriedades como cor, borda, etc., para decorar o widget do Container e aqui, a cor é usada para definir a cor do container.

  • o preenchimento do widget Container é definido usando a classe dgeInsets , que fornece a opção de especificar o valor de 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 .

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

Vários widgets filho

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

Por exemplo, o widget de linha permite o layout de seus filhos na direção horizontal, enquanto o widget de coluna permite o layout de seus filhos na direção vertical. Ao compor Linha e Coluna , um widget com qualquer nível de complexidade pode ser construído.

Vamos aprender alguns dos widgets usados ​​com freqüência nesta seção.

  • Row - Permite organizar seus filhos de forma horizontal.

  • Column - Permite organizar seus filhos de forma vertical.

  • ListView - Permite organizar seus filhos como lista.

  • GridView - Permite organizar seus filhos como galeria.

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

  • Table - Widget baseado em tabela.

  • Flow - Widget baseado em fluxo.

  • Stack - Widget baseado em pilha.

Aplicativo de layout avançado

Nesta seção, vamos aprender como criar uma interface de usuário complexa de lista de produtos com design personalizado usando widgets de layout filho único e vários.

Para tanto, siga a seqüência abaixo -

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

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

import 'package:flutter/material.dart'; 
void main() => runApp(MyApp()); 

class MyApp extends StatelessWidget {
   // This widget is the root of your application.
   @override 
   Widget build(BuildContext context) {
      return MaterialApp( 
         title: 'Flutter Demo', theme: ThemeData( 
         primarySwatch: Colors.blue,), 
         home: MyHomePage(title: 'Product layout demo home page'),
      ); 
   } 
} 
class MyHomePage extends StatelessWidget {
   MyHomePage({Key key, this.title}) : super(key: key); 
   final String title; 
      
   @override 
   Widget build(BuildContext context) {
      return Scaffold(
         appBar: AppBar(title: Text(this.title),), 
         body: Center(child: Text( 'Hello World', )), 
      ); 
   }
}
  • Here,

  • Criamos o widget MyHomePage estendendo StatelessWidget em vez do StatefulWidget padrão e removemos o código relevante.

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

  • O código para o ProductBox é o seguinte.

class ProductBox extends StatelessWidget {
   ProductBox({Key key, this.name, this.description, this.price, this.image}) 
      : super(key: key); 
   final String name; 
   final String description; 
   final int price; 
   final String image; 

   Widget build(BuildContext context) {
      return Container(
         padding: EdgeInsets.all(2), height: 120,  child: Card( 
            child: Row(
               mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: <Widget>[
                  Image.asset("assets/appimages/" +image), Expanded(
                     child: Container(
                        padding: EdgeInsets.all(5), child: Column(
                           mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
                              children: <Widget>[ 
                              
                              Text(this.name, style: TextStyle(fontWeight: 
                                 FontWeight.bold)), Text(this.description), 
                              Text("Price: " + this.price.toString()), 
                           ], 
                        )
                     )
                  )
               ]
            )
         )
      );
   }
}
  • Observe o seguinte no código -

  • ProductBox usou quatro argumentos conforme especificado abaixo -

    • nome - nome do produto

    • descrição - descrição do produto

    • preço - preço do produto

    • imagem - Imagem do produto

  • ProductBox usa sete widgets integrados conforme especificado abaixo -

    • Container
    • Expanded
    • Row
    • Column
    • Card
    • Text
    • Image
  • ProductBox é projetado usando o widget mencionado acima. A disposiçã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 -

assets: 
   - 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

Pixel.png

Laptop.png

Tablet.png

Pendrive.png

Floppy.png

Finalmente, use o widget ProductBox no widget MyHomePage conforme especificado abaixo -

class MyHomePage extends StatelessWidget { 
   MyHomePage({Key key, this.title}) : super(key: key); 
   final String title; 

   @override 
   Widget build(BuildContext context) {
      return Scaffold(
         appBar: AppBar(title:Text("Product Listing")), 
         body: ListView(
            shrinkWrap: true, padding: const EdgeInsets.fromLTRB(2.0, 10.0, 2.0, 10.0), 
            children: <Widget> [
               ProductBox(
                  name: "iPhone", 
                  description: "iPhone is the stylist phone ever", 
                  price: 1000, 
                  image: "iphone.png"
               ), 
               ProductBox(
                  name: "Pixel", 
                  description: "Pixel is the most featureful phone ever", 
                  price: 800, 
                  image: "pixel.png"
               ), 
               ProductBox( 
                  name: "Laptop", 
                  description: "Laptop is most productive development tool", 
                  price: 2000, 
                  image: "laptop.png"
               ), 
               ProductBox( 
                  name: "Tablet", 
                  description: "Tablet is the most useful device ever for meeting", 
                  price: 1500, 
                  image: "tablet.png"
               ), 
               ProductBox(
                  name: "Pendrive", 
                  description: "Pendrive is useful storage medium", 
                  price: 100, 
                  image: "pendrive.png"
               ), 
               ProductBox(
                  name: "Floppy Drive", 
                  description: "Floppy drive is useful rescue storage medium", 
                  price: 20, 
                  image: "floppy.png"
               ), 
            ],
         )
      );
   }
}
  • Aqui, usamos ProductBox como filhos do widget ListView .

  • O código completo (main.dart) do aplicativo de layout do produto (product_layout_app) é o seguinte -

import 'package:flutter/material.dart'; 
void main() => runApp(MyApp()); 

class MyApp extends StatelessWidget { 
   // This widget is the root of your application. 
   @override 
   Widget build(BuildContext context) {
      return MaterialApp(
         title: 'Flutter Demo', theme: ThemeData(
            primarySwatch: Colors.blue,
         ), 
         home: MyHomePage(title: 'Product layout demo home page'), 
      );
   }
}
class MyHomePage extends StatelessWidget { 
   MyHomePage({Key key, this.title}) : super(key: key); 
   final String title; 
   
   @override 
   Widget build(BuildContext context) { 
      return Scaffold( 
         appBar: AppBar(title: Text("Product Listing")), 
         body: ListView(
            shrinkWrap: true, 
            padding: const EdgeInsets.fromLTRB(2.0, 10.0, 2.0, 10.0), 
            children: <Widget>[ 
               ProductBox(
                  name: "iPhone", 
                  description: "iPhone is the stylist phone ever", 
                  price: 1000, 
                  image: "iphone.png"
               ), 
               ProductBox( 
                  name: "Pixel",    
                  description: "Pixel is the most featureful phone ever", 
                  price: 800, 
                  image: "pixel.png"
               ), 
               ProductBox( 
                  name: "Laptop", 
                  description: "Laptop is most productive development tool", 
                  price: 2000, 
                  image: "laptop.png"
               ), 
               ProductBox( 
                  name: "Tablet", 
                  description: "Tablet is the most useful device ever for meeting", 
                  price: 1500, 
                  image: "tablet.png"
               ), 
               ProductBox( 
                  name: "Pendrive", 
                  description: "Pendrive is useful storage medium", 
                  price: 100, 
                  image: "pendrive.png"
               ), 
               ProductBox(
                  name: "Floppy Drive", 
                  description: "Floppy drive is useful rescue storage medium", 
                  price: 20, 
                  image: "floppy.png"
               ), 
            ],
         )
      );
   }
}
class ProductBox extends StatelessWidget {
   ProductBox({Key key, this.name, this.description, this.price, this.image}) :
      super(key: key); 
   final String name; 
   final String description; 
   final int price; 
   final String image; 
   
   Widget build(BuildContext context) {
      return Container(
         padding: EdgeInsets.all(2), 
         height: 120, 
         child: Card(
            child: Row(
               mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
               children: <Widget>[ 
                  Image.asset("assets/appimages/" + image), 
                  Expanded( 
                     child: Container( 
                        padding: EdgeInsets.all(5), 
                        child: Column(    
                           mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
                           children: <Widget>[ 
                              Text(
                                 this.name, style: TextStyle(
                                    fontWeight: FontWeight.bold
                                 )
                              ),
                              Text(this.description), Text(
                                 "Price: " + this.price.toString()
                              ), 
                           ], 
                        )
                     )
                  )
               ]
            )
         )
      );
   }
}

O resultado final do aplicativo é o seguinte -

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 com a intenção de ativar um controle específico do dispositivo móvel. Os gestos são tão simples quanto tocar na tela do dispositivo móvel para ações mais complexas usadas em aplicativos de jogos.

Alguns dos gestos amplamente usados ​​são mencionados aqui -

  • Tap - Tocar a superfície do dispositivo com a ponta do dedo por um curto período e depois liberar a ponta do dedo.

  • Double Tap - Tocar duas vezes em um curto espaço de tempo.

  • Drag - Tocar a superfície do dispositivo com a ponta do dedo e, em seguida, mover a ponta do dedo de forma estável e finalmente liberar a ponta do dedo.

  • Flick - Semelhante a arrastar, mas fazendo isso de forma mais rápida.

  • Pinch - Apertar a superfície do dispositivo com dois dedos.

  • Spread/Zoom - Oposto de beliscar.

  • Panning - 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 fornece 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 em um widget, o widget pode ser colocado dentro do widget GestureDetector. GestureDetector irá capturar o gesto e despachar vários eventos com base no gesto.

Alguns dos gestos e os eventos correspondentes são fornecidos abaixo -

  • Tap
    • onTapDown
    • onTapUp
    • onTap
    • onTapCancel
  • Toque duplo
    • onDoubleTap
  • Pressão longa
    • onLongPress
  • Arrasto vertical
    • onVerticalDragStart
    • onVerticalDragUpdate
    • onVerticalDragEnd
  • Arrasto horizontal
    • onHorizontalDragStart
    • onHorizontalDragUpdate
    • onHorizontalDragEnd
  • Pan
    • onPanStart
    • onPanUpdate
    • 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 -

body: Center( 
   child: GestureDetector( 
      onTap: () { 
         _showDialog(context); 
      }, 
      child: Text( 'Hello World', ) 
   ) 
),
  • Observe que aqui colocamos o widget GestureDetector acima do widget Texto na hierarquia do widget, capturamos o evento onTap e finalmente mostramos uma janela de diálogo.

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

// user defined function void _showDialog(BuildContext context) { 
   // flutter defined function 
   showDialog( 
      context: context, builder: (BuildContext context) { 
         // return object of type Dialog
         return AlertDialog( 
            title: new Text("Message"), 
            content: new Text("Hello World"),   
            actions: <Widget>[ 
               new FlatButton( 
                  child: new Text("Close"),  
                  onPressed: () {   
                     Navigator.of(context).pop();  
                  }, 
               ), 
            ], 
         ); 
      }, 
   ); 
}
  • O aplicativo será recarregado no dispositivo usando o recurso Hot Reload. Agora, basta clicar na mensagem, Hello World e ela mostrará a caixa de diálogo abaixo -

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

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

import 'package:flutter/material.dart'; 
void main() => runApp(MyApp()); 

class MyApp extends StatelessWidget { 
   // This widget is the root of your application.    
   @override 
   Widget build(BuildContext context) {
      return MaterialApp(
         title: 'Hello World Demo Application', 
         theme: ThemeData( primarySwatch: Colors.blue,), 
         home: MyHomePage(title: 'Home page'), 
      ); 
   }
}
class MyHomePage extends StatelessWidget {
   MyHomePage({Key key, this.title}) : super(key: key); 
   final String title; 
   
   // user defined function 
   void _showDialog(BuildContext context) { 
      // flutter defined function showDialog( 
         context: context, builder: (BuildContext context) { 
            // return object of type Dialog return AlertDialog(
               title: new Text("Message"), 
               content: new Text("Hello World"),   
               actions: <Widget>[
                  new FlatButton(
                     child: new Text("Close"), 
                     onPressed: () {   
                        Navigator.of(context).pop();  
                     }, 
                  ), 
               ],
            );
         },
      );
   }
   @override 
   Widget build(BuildContext context) {
      return Scaffold(
         appBar: AppBar(title: Text(this.title),),
         body: Center(
            child: GestureDetector( 
               onTap: () {
                  _showDialog(context);
               },
            child: Text( 'Hello World', )
            )
         ),
      );
   }
}

Por fim, 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, em seguida, enviará os seguintes eventos -

  • PointerDownEvent
  • PointerMoveEvent
  • PointerUpEvent
  • PointerCancelEvent

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

  • Dismissible - Suporta gesto de movimento para dispensar o widget.

  • Draggable - Suporta gesto de arrastar para mover o widget.

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

  • DragTarget- Aceita qualquer widget arrastável

  • IgnorePointer - Oculta o widget e seus filhos do processo de detecção de gestos.

  • AbsorbPointer - Interrompe o próprio processo de detecção de gestos e, portanto, qualquer widget sobreposto também não pode participar do processo de detecção de gestos e, portanto, nenhum evento é gerado.

  • Scrollable - Suporte a rolagem do conteúdo disponível dentro do widget.

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

Vamos considerar um aplicativo simples de carrinho de compras.

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

  • Depois que o usuário estiver logado, o aplicativo deve manter os detalhes do usuário conectado em toda 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 o check-out do carrinho.

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

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

  • Ephemeral- Duram alguns segundos, como o estado atual de uma animação, ou uma única página, como a avaliação atual de um produto. Flutter suporta seu por meio de StatefulWidget.

  • app state- Por ú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.

Navegação e roteamento

Em qualquer aplicativo, navegar de uma página / tela para outra define o fluxo de trabalho do aplicativo. A forma como a navegação de um aplicativo é tratada é chamada de Roteamento. O 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 um aplicativo.

MaterialPageRoute

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

MaterialPageRoute(builder: (context) => Widget())

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

Navigation.push

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

Navigator.push( context, MaterialPageRoute(builder: (context) => Widget()), );

Navigation.pop

Navigation.pop é usado para navegar para a tela anterior.

Navigator.pop(context);

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 inclua ativos dentro do arquivo pubspec.yaml.

flutter:
   assets: 
   - 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.

import 'package:flutter/material.dart'; 
void main() => runApp(MyApp()); 

class MyApp extends StatelessWidget { 
   // This widget is the root of your application. 
   @override 
   Widget build(BuildContext context) { 
      return MaterialApp( 
         title: 'Flutter Demo', 
         theme: ThemeData( 
            primarySwatch: Colors.blue, 
         ), 
         home: MyHomePage(
            title: 'Product state demo home page'
         ),
      );
   }
}
class MyHomePage extends StatelessWidget {
   MyHomePage({Key key, this.title}) : super(key: key);
   final String title;
   @override 
   Widget build(BuildContext context) {
      return Scaffold(
         appBar: AppBar(
            title: Text(this.title), 
         ), 
         body: Center(
            child: Text('Hello World',)
         ), 
      ); 
   } 
}
  • Vamos criar uma classe de produto para organizar as informações do produto.

class Product { 
   final String name; 
   final String description; 
   final int price; 
   final String image; 
   Product(this.name, this.description, this.price, this.image); 
}
  • Vamos escrever um método getProducts na classe Product para gerar nossos registros de produto fictícios.

static List<Product> getProducts() {
   List<Product> items = <Product>[]; 
   
   items.add(
      Product( 
         "Pixel", 
         "Pixel is the most feature-full phone ever", 800, 
         "pixel.png"
      )
   ); 
   items.add(
      Product(
         "Laptop", 
         "Laptop is most productive development tool", 
         2000, "
         laptop.png"
      )
   ); 
   items.add(
      Product( 
         "Tablet", 
         "Tablet is the most useful device ever for meeting", 
         1500, 
         "tablet.png"
      )
   ); 
   items.add(
      Product( 
         "Pendrive", 
         "Pendrive is useful storage medium",
         100, 
         "pendrive.png"
      )
   ); 
   items.add(
      Product( 
         "Floppy Drive", 
         "Floppy drive is useful rescue storage medium", 
         20, 
         "floppy.png"
      )
   ); 
   return items; 
}
import product.dart in main.dart
import 'Product.dart';
  • Vamos incluir nosso novo widget, RatingBox.

class RatingBox extends StatefulWidget {
   @override 
   _RatingBoxState createState() =>_RatingBoxState(); 
} 
class _RatingBoxState extends State<RatingBox> {
   int _rating = 0; 
   void _setRatingAsOne() {
      setState(() {
         _rating = 1; 
      }); 
   } 
   void _setRatingAsTwo() {
      setState(() {
         _rating = 2; 
      }); 
   }
   void _setRatingAsThree() {
      setState(() {
         _rating = 3;
      });
   }
   Widget build(BuildContext context) {
      double _size = 20; 
      print(_rating); 
      return Row(
         mainAxisAlignment: MainAxisAlignment.end, 
         crossAxisAlignment: CrossAxisAlignment.end, 
         mainAxisSize: MainAxisSize.max, 
         children: <Widget>[
            Container(
               padding: EdgeInsets.all(0), 
               child: IconButton(
                  icon: (
                     _rating >= 1? 
                     Icon( 
                        Icons.star, 
                        size: _size, 
                     ) 
                     : Icon(
                        Icons.star_border, 
                        size: _size, 
                     )
                  ), 
                  color: Colors.red[500], 
                  onPressed: _setRatingAsOne, 
                  iconSize: _size, 
               ), 
            ), 
            Container(
               padding: EdgeInsets.all(0), 
               child: IconButton(
                  icon: (
                     _rating >= 2? 
                     Icon(
                        Icons.star, 
                        size: _size, 
                     ) 
                     : Icon(
                        Icons.star_border, 
                        size: _size, 
                     )
                  ), 
                  color: Colors.red[500], 
                  onPressed: _setRatingAsTwo, 
                  iconSize: _size, 
               ), 
            ), 
            Container(
               padding: EdgeInsets.all(0), 
               child: IconButton(
                  icon: (
                     _rating >= 3 ? 
                     Icon(
                        Icons.star, 
                        size: _size, 
                     ) 
                     : Icon( 
                        Icons.star_border, 
                        size: _size, 
                     )
                  ), 
                  color: Colors.red[500], 
                  onPressed: _setRatingAsThree, 
                  iconSize: _size, 
               ), 
            ), 
         ], 
      ); 
   }
}
  • Vamos modificar nosso widget ProductBox para funcionar com nossa nova classe Product.

class ProductBox extends StatelessWidget {    
   ProductBox({Key key, this.item}) : super(key: key); 
   final Product item; 
   
   Widget build(BuildContext context) {
      return Container(
         padding: EdgeInsets.all(2), 
         height: 140, 
         child: Card( 
            child: Row(
               mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
               children: <Widget>[ 
                  Image.asset("assets/appimages/" + this.item.image), 
                  Expanded(
                     child: Container(
                        padding: EdgeInsets.all(5), 
                        child: Column(
                           mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
                           children: <Widget>[
                              Text(this.item.name, 
                              style: TextStyle(fontWeight: FontWeight.bold)), 
                              Text(this.item.description), 
                              Text("Price: " + this.item.price.toString()), 
                              RatingBox(), 
                           ], 
                        )
                     )
                  )
               ]
            ), 
         )
      ); 
   }
}

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

class MyHomePage extends StatelessWidget { 
   MyHomePage({Key key, this.title}) : super(key: key); 
   final String title; 
   final items = Product.getProducts(); 
   
   @override 
   Widget build(BuildContext context) { 
      return Scaffold( appBar: AppBar(title: Text("Product Navigation")), 
      body: ListView.builder( 
         itemCount: items.length, 
         itemBuilder: (context, index) {
            return GestureDetector( 
               child: ProductBox(item: items[index]), 
               onTap: () { 
                  Navigator.push( 
                     context, MaterialPageRoute( 
                        builder: (context) => ProductPage(item: items[index]), 
                     ), 
                  ); 
               }, 
            ); 
         }, 
      )); 
   } 
}

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

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

class ProductPage extends StatelessWidget { 
   ProductPage({Key key, this.item}) : super(key: key); 
   final Product item; 
   
   @override 
   Widget build(BuildContext context) {
      return Scaffold(
         appBar: AppBar( 
            title: Text(this.item.name), 
         ), 
         body: Center(
            child: Container(
               padding: EdgeInsets.all(0), 
               child: Column(
                  mainAxisAlignment: MainAxisAlignment.start, 
                  crossAxisAlignment: CrossAxisAlignment.start, 
                  children: <Widget>[
                     Image.asset("assets/appimages/" + this.item.image), 
                     Expanded(
                        child: Container(
                           padding: EdgeInsets.all(5), 
                           child: Column(
                              mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
                              children: <Widget>[
                                 Text(
                                    this.item.name, style: TextStyle(
                                       fontWeight: FontWeight.bold
                                    )
                                 ), 
                                 Text(this.item.description), 
                                 Text("Price: " + this.item.price.toString()), 
                                 RatingBox(),
                              ], 
                           )
                        )
                     )
                  ]
               ), 
            ), 
         ), 
      ); 
   } 
}

O código completo do aplicativo é o seguinte -

import 'package:flutter/material.dart'; 
void main() => runApp(MyApp()); 

class Product {
   final String name; 
   final String description; 
   final int price; 
   final String image; 
   Product(this.name, this.description, this.price, this.image); 
   
   static List<Product> getProducts() {
      List<Product> items = <Product>[]; 
      items.add(
         Product(
            "Pixel", 
            "Pixel is the most featureful phone ever", 
            800, 
            "pixel.png"
         )
      );
      items.add(
         Product(
            "Laptop", 
            "Laptop is most productive development tool", 
            2000, 
            "laptop.png"
         )
      ); 
      items.add(
         Product(
            "Tablet", 
            "Tablet is the most useful device ever for meeting", 
            1500, 
            "tablet.png"
         )
      ); 
      items.add(
         Product( 
            "Pendrive", 
            "iPhone is the stylist phone ever", 
            100, 
            "pendrive.png"
         )
      ); 
      items.add(
         Product(
            "Floppy Drive", 
            "iPhone is the stylist phone ever", 
            20, 
            "floppy.png"
         )
      ); 
      items.add(
         Product(
            "iPhone", 
            "iPhone is the stylist phone ever", 
            1000, 
            "iphone.png"
         )
      ); 
      return items; 
   }
}
class MyApp extends StatelessWidget {
   // This widget is the root of your application. 
   @override 
   Widget build(BuildContext context) {
      return MaterialApp(
         title: 'Flutter Demo', 
         theme: ThemeData( 
            primarySwatch: Colors.blue, 
         ), 
         home: MyHomePage(title: 'Product Navigation demo home page'), 
      ); 
   }
}
class MyHomePage extends StatelessWidget {
   MyHomePage({Key key, this.title}) : super(key: key); 
   final String title; 
   final items = Product.getProducts(); 
   
   @override 
   Widget build(BuildContext context) {
      return Scaffold(
         appBar: AppBar(title: Text("Product Navigation")), 
         body: ListView.builder( 
            itemCount: items.length, 
            itemBuilder: (context, index) { 
               return GestureDetector( 
                  child: ProductBox(item: items[index]), 
                  onTap: () { 
                     Navigator.push( 
                        context, 
                        MaterialPageRoute( 
                           builder: (context) => ProductPage(item: items[index]), 
                        ), 
                     ); 
                  }, 
               ); 
            }, 
         )
      ); 
   }
} 
class ProductPage extends StatelessWidget {
   ProductPage({Key key, this.item}) : super(key: key); 
   final Product item; 
   
   @override 
   Widget build(BuildContext context) {
      return Scaffold(
         appBar: AppBar(
            title: Text(this.item.name), 
         ), 
         body: Center(
            child: Container( 
               padding: EdgeInsets.all(0), 
               child: Column( 
                  mainAxisAlignment: MainAxisAlignment.start, 
                  crossAxisAlignment: CrossAxisAlignment.start, 
                  children: <Widget>[ 
                     Image.asset("assets/appimages/" + this.item.image), 
                     Expanded( 
                        child: Container( 
                           padding: EdgeInsets.all(5), 
                           child: Column( 
                              mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
                              children: <Widget>[ 
                                 Text(this.item.name, style: TextStyle(fontWeight: FontWeight.bold)), 
                                 Text(this.item.description), 
                                 Text("Price: " + this.item.price.toString()), 
                                 RatingBox(), 
                              ], 
                           )
                        )
                     ) 
                  ]
               ), 
            ), 
         ), 
      ); 
   } 
}
class RatingBox extends StatefulWidget { 
   @override 
   _RatingBoxState createState() => _RatingBoxState(); 
} 
class _RatingBoxState extends State<RatingBox> { 
   int _rating = 0;
   void _setRatingAsOne() {
      setState(() {
         _rating = 1; 
      }); 
   }
   void _setRatingAsTwo() {
      setState(() {
         _rating = 2; 
      }); 
   } 
   void _setRatingAsThree() { 
      setState(() {
         _rating = 3; 
      }); 
   }
   Widget build(BuildContext context) {
      double _size = 20; 
      print(_rating); 
      return Row(
         mainAxisAlignment: MainAxisAlignment.end, 
         crossAxisAlignment: CrossAxisAlignment.end, 
         mainAxisSize: MainAxisSize.max, 
         children: <Widget>[
            Container(
               padding: EdgeInsets.all(0), 
               child: IconButton(
                  icon: (
                     _rating >= 1 ? Icon( 
                        Icons.star, 
                        size: _size, 
                     ) 
                     : Icon( 
                        Icons.star_border, 
                        size: _size, 
                     )
                  ), 
                  color: Colors.red[500], 
                  onPressed: _setRatingAsOne, 
                  iconSize: _size, 
               ), 
            ), 
            Container(
               padding: EdgeInsets.all(0), 
               child: IconButton( 
                  icon: (
                     _rating >= 2 ? 
                     Icon( 
                        Icons.star, 
                        size: _size, 
                     ) 
                     : Icon( 
                        Icons.star_border, 
                        size: _size, 
                     )
                  ), 
                  color: Colors.red[500], 
                  onPressed: _setRatingAsTwo, 
                  iconSize: _size, 
               ), 
            ), 
            Container(
               padding: EdgeInsets.all(0), 
               child: IconButton(
                  icon: (
                     _rating >= 3 ? 
                     Icon( 
                        Icons.star, 
                        size: _size, 
                     )
                     : Icon( 
                        Icons.star_border, 
                        size: _size, 
                     )
                  ), 
                  color: Colors.red[500], 
                  onPressed: _setRatingAsThree, 
                  iconSize: _size, 
               ), 
            ), 
         ], 
      ); 
   } 
} 
class ProductBox extends StatelessWidget {
   ProductBox({Key key, this.item}) : super(key: key); 
   final Product item; 
   
   Widget build(BuildContext context) {
      return Container(
         padding: EdgeInsets.all(2), 
         height: 140, 
         child: Card(
            child: Row(
               mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
               children: <Widget>[ 
                  Image.asset("assets/appimages/" + this.item.image), 
                  Expanded( 
                     child: Container( 
                        padding: EdgeInsets.all(5), 
                        child: Column( 
                           mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
                           children: <Widget>[ 
                              Text(this.item.name, style: TextStyle(fontWeight: FontWeight.bold)), Text(this.item.description), 
                              Text("Price: " + this.item.price.toString()), 
                              RatingBox(), 
                           ], 
                        )
                     )
                  ) 
               ]
            ), 
         )
      ); 
   } 
}

Execute o aplicativo e clique em qualquer um dos itens do produto. Ele irá 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 da seguinte forma -

A animação é um procedimento complexo em qualquer aplicativo móvel. Apesar de sua complexidade, o Animation aprimora a experiência do usuário a um novo nível e fornece uma interação rica 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 estrutura simples e intuitiva para desenvolver todos os tipos de animações.

Introdução

Animação é um processo de mostrar uma série de imagens / imagens em uma ordem particular dentro de 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 um widget para desaparecer, o valor inicial será a opacidade total e o valor final será a opacidade zero.

  • Os valores intermediários podem ser lineares ou não lineares (curva) por natureza e podem ser configurados. Entenda que a animação funciona como está configurada. Cada configuração fornece uma sensação diferente para a animação. Por exemplo, o esmaecimento 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) da animação.

  • A capacidade de controlar o processo de animação, como iniciar a animação, interromper a animação, repetir a animação para definir o 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, ele 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 ao longo de uma certa duração. As classes de animação mais comuns são -

  • Animation<double> - interpolar valores entre dois números decimais

  • Animation<Color> - interpolar cores entre duas cores

  • Animation<Size> - interpolar tamanhos entre dois tamanhos

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

controller = AnimationController(duration: const Duration(seconds: 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 usada para otimizar o recurso usado 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 como abaixo -

controller = AnimationController(duration: const Duration(seconds: 2), vsync: this); 
animation = CurvedAnimation(parent: controller, curve: Curves.easeIn)

Tween <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.

AnimationController controller = AnimationController( 
   duration: const Duration(milliseconds: 1000), 
vsync: this); Animation<int> customTween = IntTween(
   begin: 0, end: 255).animate(controller);
  • Tween também pode ser usado junto com CurvedAnimation como abaixo -

AnimationController controller = AnimationController(
   duration: const Duration(milliseconds: 500), vsync: this); 
final Animation curve = CurvedAnimation(parent: controller, curve: Curves.easeOut); 
Animation<int> customTween = IntTween(begin: 0, end: 255).animate(curve);

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

Fluxo de trabalho da Animação Flutter

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

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

AnimationController(duration: const Duration(seconds: 2), vsync: this); 
animation = Tween<double>(begin: 0, end: 300).animate(controller); 
controller.forward();
  • Adicione ouvinte baseado em animação, addListener para alterar o estado do widget.

animation = Tween<double>(begin: 0, end: 300).animate(controller) ..addListener(() {
   setState(() { 
      // The state that has changed here is the animation object’s value. 
   }); 
});
  • Widgets embutidos, 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 de animação durante o processo de construção do widget e aplique-os para largura, altura ou qualquer propriedade relevante em vez do valor original.

child: Container( 
   height: animation.value, 
   width: animation.value, 
   child: <Widget>, 
)

Aplicação 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 inclua ativos dentro do arquivo pubspec.yaml.

flutter: 
   assets: 
   - assets/appimages/floppy.png 
   - assets/appimages/iphone.png 
   - assets/appimages/laptop.png 
   - assets/appimages/pendrive.png 
   - assets/appimages/pixel.png 
   - assets/appimages/tablet.png
  • Remova o código de inicialização padrão (main.dart).

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

import 'package:flutter/material.dart'; 
void main() => runApp(MyApp());
  • Crie o widget MyApp derivado de StatefulWidgtet.

class MyApp extends StatefulWidget { 
   _MyAppState createState() => _MyAppState(); 
}
  • Crie o widget _MyAppState e implemente initState e descarte além do método de construção padrão.

class _MyAppState extends State<MyApp> with SingleTickerProviderStateMixin { 
   Animation<double> animation; 
   AnimationController controller; 
   @override void initState() {
      super.initState(); 
      controller = AnimationController(
         duration: const Duration(seconds: 10), vsync: this
      ); 
      animation = Tween<double>(begin: 0.0, end: 1.0).animate(controller); 
      controller.forward(); 
   } 
   // This widget is the root of your application. 
   @override 
   Widget build(BuildContext context) {
      controller.forward(); 
      return MaterialApp(
         title: 'Flutter Demo',
         theme: ThemeData(primarySwatch: Colors.blue,), 
         home: MyHomePage(title: 'Product layout demo home page', animation: animation,)
      ); 
   } 
   @override 
   void dispose() {
      controller.dispose();
      super.dispose();
   }
}

Aqui,

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

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

  • No método de construção, envie a 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 extends StatelessWidget {
   ProductBox({Key key, this.name, this.description, this.price, this.image})
      : super(key: key);
   final String name; 
   final String description; 
   final int price; 
   final String image; 
   
   Widget build(BuildContext context) {
      return Container(
         padding: EdgeInsets.all(2), 
         height: 140, 
         child: Card( 
            child: Row( 
               mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
               children: <Widget>[ 
                  Image.asset("assets/appimages/" + image), 
                  Expanded( 
                     child: Container( 
                        padding: EdgeInsets.all(5), 
                        child: Column( 
                           mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
                           children: <Widget>[ 
                              Text(this.name, style: 
                                 TextStyle(fontWeight: FontWeight.bold)), 
                              Text(this.description), 
                                 Text("Price: " + this.price.toString()), 
                           ], 
                        )
                     )
                  )
               ]
            )
         )
      ); 
   }
}
  • Crie um novo widget, MyAnimatedWidget para fazer uma animação de fade simples usando opacidade.

class MyAnimatedWidget extends StatelessWidget { 
   MyAnimatedWidget({this.child, this.animation}); 
      
   final Widget child; 
   final Animation<double> animation; 
   
   Widget build(BuildContext context) => Center( 
   child: AnimatedBuilder(
      animation: animation, 
      builder: (context, child) => Container( 
         child: Opacity(opacity: animation.value, child: child), 
      ), 
      child: child), 
   ); 
}
  • Aqui, usamos o AniatedBuilder para fazer nossa animação. AnimatedBuilder é um widget que constrói seu conteúdo enquanto faz a animação ao mesmo tempo. Ele aceita um objeto de animação para obter o valor da animação atual. Usamos o valor da animação, animation.value, para definir a opacidade do widget filho. Na verdade, o widget irá animar o widget filho usando o conceito de opacidade.

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

class MyHomePage extends StatelessWidget {
   MyHomePage({Key key, this.title, this.animation}) : super(key: key); 
   
   final String title; 
   final Animation<double> 
   animation; 
   
   @override 
   Widget build(BuildContext context) {
      return Scaffold(
         appBar: AppBar(title: Text("Product Listing")),body: ListView(
            shrinkWrap: true,
            padding: const EdgeInsets.fromLTRB(2.0, 10.0, 2.0, 10.0), 
            children: <Widget>[
               FadeTransition(
                  child: ProductBox(
                     name: "iPhone", 
                     description: "iPhone is the stylist phone ever", 
                     price: 1000, 
                     image: "iphone.png"
                  ), opacity: animation
               ), 
               MyAnimatedWidget(child: ProductBox(
                  name: "Pixel", 
                  description: "Pixel is the most featureful phone ever", 
                  price: 800, 
                  image: "pixel.png"
               ), animation: animation), 
               ProductBox(
                  name: "Laptop", 
                  description: "Laptop is most productive development tool", 
                  price: 2000, 
                  image: "laptop.png"
               ), 
               ProductBox(
                  name: "Tablet", 
                  description: "Tablet is the most useful device ever for meeting", 
                  price: 1500, 
                  image: "tablet.png"
               ), 
               ProductBox(
                  name: "Pendrive", 
                  description: "Pendrive is useful storage medium", 
                  price: 100, 
                  image: "pendrive.png"
               ),
               ProductBox(
                  name: "Floppy Drive", 
                  description: "Floppy drive is useful rescue storage medium", 
                  price: 20, 
                  image: "floppy.png"
               ),
            ],
         )
      );
   }
}

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 -

import 'package:flutter/material.dart'; 
void main() => runApp(MyApp()); 

class MyApp extends StatefulWidget { 
   _MyAppState createState() => _MyAppState(); 
} 
class _MyAppState extends State<MyApp> with SingleTickerProviderStateMixin {
   Animation<double> animation; 
   AnimationController controller; 
   
   @override 
   void initState() {
      super.initState(); 
      controller = AnimationController(
         duration: const Duration(seconds: 10), vsync: this); 
      animation = Tween<double>(begin: 0.0, end: 1.0).animate(controller); 
      controller.forward(); 
   } 
   // This widget is the root of your application. 
   @override 
   Widget build(BuildContext context) {
      controller.forward(); 
      return MaterialApp( 
         title: 'Flutter Demo', theme: ThemeData(primarySwatch: Colors.blue,), 
         home: MyHomePage(title: 'Product layout demo home page', animation: animation,) 
      ); 
   } 
   @override 
   void dispose() {
      controller.dispose();
      super.dispose(); 
   } 
}
class MyHomePage extends StatelessWidget { 
   MyHomePage({Key key, this.title, this.animation}): super(key: key);
   final String title; 
   final Animation<double> animation; 
   
   @override 
   Widget build(BuildContext context) {
      return Scaffold(
         appBar: AppBar(title: Text("Product Listing")), 
         body: ListView(
            shrinkWrap: true, 
            padding: const EdgeInsets.fromLTRB(2.0, 10.0, 2.0, 10.0), 
            children: <Widget>[
               FadeTransition(
                  child: ProductBox(
                     name: "iPhone", 
                     description: "iPhone is the stylist phone ever", 
                     price: 1000, 
                     image: "iphone.png"
                  ), 
                  opacity: animation
               ), 
               MyAnimatedWidget(
                  child: ProductBox( 
                     name: "Pixel", 
                     description: "Pixel is the most featureful phone ever", 
                     price: 800, 
                     image: "pixel.png"
                  ), 
                  animation: animation
               ), 
               ProductBox( 
                  name: "Laptop", 
                  description: "Laptop is most productive development tool", 
                  price: 2000, 
                  image: "laptop.png"
               ), 
               ProductBox(
                  name: "Tablet",
                  description: "Tablet is the most useful device ever for meeting",
                  price: 1500, 
                  image: "tablet.png"
               ), 
               ProductBox(
                  name: "Pendrive", 
                  description: "Pendrive is useful storage medium", 
                  price: 100, 
                  image: "pendrive.png"
               ), 
               ProductBox(
                  name: "Floppy Drive", 
                  description: "Floppy drive is useful rescue storage medium", 
                  price: 20, 
                  image: "floppy.png"
               ), 
            ], 
         )
      ); 
   } 
} 
class ProductBox extends StatelessWidget { 
   ProductBox({Key key, this.name, this.description, this.price, this.image}) :
      super(key: key);
   final String name; 
   final String description; 
   final int price; 
   final String image; 
   Widget build(BuildContext context) {
      return Container(
         padding: EdgeInsets.all(2), 
         height: 140, 
         child: Card(
            child: Row(
               mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
               children: <Widget>[ 
                  Image.asset("assets/appimages/" + image), 
                  Expanded(
                     child: Container( 
                        padding: EdgeInsets.all(5), 
                        child: Column( 
                           mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
                           children: <Widget>[ 
                              Text(
                                 this.name, style: TextStyle(
                                    fontWeight: FontWeight.bold
                                 )
                              ), 
                              Text(this.description), Text(
                                 "Price: " + this.price.toString()
                              ), 
                           ], 
                        )
                     )
                  ) 
               ]
            )
         )
      ); 
   } 
}
class MyAnimatedWidget extends StatelessWidget { 
   MyAnimatedWidget({this.child, this.animation}); 
   final Widget child; 
   final Animation<double> animation; 
 
   Widget build(BuildContext context) => Center( 
      child: AnimatedBuilder(
         animation: animation, 
         builder: (context, child) => Container( 
            child: Opacity(opacity: animation.value, child: child), 
         ), 
         child: child
      ), 
   ); 
}
  • Compile e execute o aplicativo para ver os resultados. A versão inicial e final do aplicativo é a seguinte -

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 é por meio de um protocolo de mensagens simples. Flutter code, Client e o código da plataforma e Host se ligam a um canal de mensagem comum. O cliente envia uma mensagem ao Host através do Canal de Mensagens. O Host escuta no Canal de Mensagem, recebe a mensagem e faz a funcionalidade necessária e, por fim, retorna o resultado ao Cliente através do Canal de Mensagem.

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

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

Vamos escrever um aplicativo simples para abrir um navegador usando Android SDK e entender como

  • Crie um novo aplicativo Flutter no Android Studio, flutter_browser_app

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

import 'package:flutter/material.dart'; 
void main() => runApp(MyApp()); 
class MyApp extends StatelessWidget { 
   @override 
   Widget build(BuildContext context) {
      return MaterialApp(
         title: 'Flutter Demo', 
         theme: ThemeData( 
            primarySwatch: Colors.blue, 
         ), 
         home: MyHomePage(title: 'Flutter Demo Home Page'),
      );
   }
}
class MyHomePage extends StatelessWidget { 
   MyHomePage({Key key, this.title}) : super(key: key); 
   final String title; 
   
   @override 
   Widget build(BuildContext context) {
      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 definir seu método onPressed como nulo.

  • Agora, importe os seguintes pacotes -

import 'dart:async'; 
import 'package:flutter/services.dart';
  • Aqui, services.dart inclui a funcionalidade para invocar o código específico da plataforma.

  • Crie um novo canal de mensagem no widget MyHomePage.

static const platform = const 
MethodChannel('flutterapp.tutorialspoint.com/browser');
  • Escreva um método, _openBrowser para invocar o método específico da plataforma, o método openBrowser por meio do canal de mensagem.

Future<void> _openBrowser() async { 
   try {
      final int result = await platform.invokeMethod(
         'openBrowser', <String, String>{ 
            'url': "https://flutter.dev" 
         }
      ); 
   } 
   on PlatformException catch (e) { 
      // Unable to open the browser 
      print(e); 
   }
}

Aqui, usamos platform.invokeMethod para invocar openBrowser (explicado nas próximas etapas). openBrowser tem um argumento, url, para abrir um url específico.

  • 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 -

import android.app.Activity; 
import android.content.Intent; 
import android.net.Uri; 
import android.os.Bundle; 

import io.flutter.app.FlutterActivity; 
import io.flutter.plugin.common.MethodCall; 
import io.flutter.plugin.common.MethodChannel; 
import io.flutter.plugin.common.MethodChannel.MethodCallHandler; 
import io.flutter.plugin.common.MethodChannel.Result; 
import 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", 
      "Browser cannot be opened without foreground 
      activity", null); 
      return; 
   } 
   Intent intent = new Intent(Intent.ACTION_VIEW); 
   intent.setData(Uri.parse(url)); 
   
   activity.startActivity(intent); 
   result.success((Object) true); 
}
  • 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")) {
         openBrowser(call, result, url); 
      } else { 
         result.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 correto verificando a mensagem. O método onMethodCall extrai o url da mensagem e invoca o openBrowser apenas quando a chamada do método é openBrowser. Caso contrário, ele retorna o método notImplemented.

O código-fonte completo do aplicativo é o seguinte -

main.dart

MainActivity.java

package com.tutorialspoint.flutterapp.flutter_browser_app; 

import android.app.Activity; 
import android.content.Intent; 
import android.net.Uri; 
import android.os.Bundle; 
import io.flutter.app.FlutterActivity; 
import io.flutter.plugin.common.MethodCall; 
import io.flutter.plugin.common.MethodChannel.Result; 
import io.flutter.plugins.GeneratedPluginRegistrant; 

public class MainActivity extends FlutterActivity { 
   private static final String CHANNEL = "flutterapp.tutorialspoint.com/browser"; 
   @Override 
   protected void onCreate(Bundle savedInstanceState) { 
      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(call, result, url); 
               } else { 
                  result.notImplemented(); 
               }
            }
         }
      ); 
   }
   private void openBrowser(MethodCall call, Result result, String url) {
      Activity activity = this; if (activity == null) {
         result.error(
            "ACTIVITY_NOT_AVAILABLE", "Browser cannot be opened without foreground activity", null
         ); 
         return; 
      } 
      Intent intent = new Intent(Intent.ACTION_VIEW); 
      intent.setData(Uri.parse(url)); 
      activity.startActivity(intent); 
      result.success((Object) true); 
   }
}

main.dart

import 'package:flutter/material.dart'; 
import 'dart:async'; 
import 'package:flutter/services.dart'; 

void main() => runApp(MyApp()); 
class MyApp extends StatelessWidget {
   @override 
   Widget build(BuildContext context) {
      return MaterialApp(
         title: 'Flutter Demo', 
         theme: ThemeData( 
            primarySwatch: Colors.blue, 
         ), 
         home: MyHomePage(
            title: 'Flutter Demo Home Page'
         ), 
      ); 
   }
}
class MyHomePage extends StatelessWidget {
   MyHomePage({Key key, this.title}) : super(key: key); 
   final String title; 
   static const platform = const MethodChannel('flutterapp.tutorialspoint.com/browser'); 
   Future<void> _openBrowser() async {
      try {
         final int result = await platform.invokeMethod('openBrowser', <String, String>{ 
            'url': "https://flutter.dev" 
         });
      }
      on PlatformException catch (e) { 
         // Unable to open the browser print(e); 
      } 
   }
   @override 
   Widget build(BuildContext context) {
      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 do navegador - página inicial é mostrado na imagem aqui -

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 os passos 2 - 6 como no capítulo anterior.

  • Inicie o XCode e clique em File → Open

  • Escolha o projeto xcode no diretório ios do nosso projeto flutter.

  • Abra AppDelegate.m em Runner → Runner path. Ele contém o seguinte código -

#include "AppDelegate.h" 
#include "GeneratedPluginRegistrant.h" 
@implementation AppDelegate 

- (BOOL)application:(UIApplication *)application
   didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
      // [GeneratedPluginRegistrant registerWithRegistry:self];
      // Override point for customization after application launch.
      return [super application:application didFinishLaunchingWithOptions:launchOptions];
   } 
@end
  • Adicionamos um método, openBrowser, para abrir o navegador com o url especificado. Ele aceita um único argumento, url.

- (void)openBrowser:(NSString *)urlString { 
   NSURL *url = [NSURL URLWithString:urlString]; 
   UIApplication *application = [UIApplication sharedApplication]; 
   [application openURL:url]; 
}
  • No método didFinishLaunchingWithOptions, encontre o controlador e defina-o na variável do controlador.

FlutterViewController* controller = (FlutterViewController*)self.window.rootViewController;
  • No método didFinishLaunchingWithOptions, defina o canal do navegador como flutterapp.tutorialspoint.com/browse -

FlutterMethodChannel* browserChannel = [
   FlutterMethodChannel methodChannelWithName:
   @"flutterapp.tutorialspoint.com/browser" binaryMessenger:controller];
  • Crie uma variável, fracaSelf e defina a classe atual -

__weak typeof(self) weakSelf = self;
  • Agora, implemente setMethodCallHandler. Chame openBrowser combinando call.method. Obtenha o url invocando call.arguments e passe-o ao chamar openBrowser.

[browserChannel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
   if ([@"openBrowser" isEqualToString:call.method]) { 
      NSString *url = call.arguments[@"url"];   
      [weakSelf openBrowser:url]; 
   } else { result(FlutterMethodNotImplemented); } 
}];
  • O código completo é o seguinte -

#include "AppDelegate.h" 
#include "GeneratedPluginRegistrant.h" 
@implementation AppDelegate 

- (BOOL)application:(UIApplication *)application 
   didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
   
   // custom code starts 
   FlutterViewController* controller = (FlutterViewController*)self.window.rootViewController; 
   FlutterMethodChannel* browserChannel = [
      FlutterMethodChannel methodChannelWithName:
      @"flutterapp.tutorialspoint.com /browser" binaryMessenger:controller]; 
   
   __weak typeof(self) weakSelf = self; 
   [browserChannel setMethodCallHandler:^(
      FlutterMethodCall* call, FlutterResult result) { 
      
      if ([@"openBrowser" isEqualToString:call.method]) { 
         NSString *url = call.arguments[@"url"];
         [weakSelf openBrowser:url]; 
      } else { result(FlutterMethodNotImplemented); } 
   }]; 
   // custom code ends 
   [GeneratedPluginRegistrant registerWithRegistry:self]; 
   
   // Override point for customization after application launch. 
   return [super application:application didFinishLaunchingWithOptions:launchOptions]; 
}
- (void)openBrowser:(NSString *)urlString { 
   NSURL *url = [NSURL URLWithString:urlString]; 
   UIApplication *application = [UIApplication sharedApplication]; 
   [application openURL:url]; 
} 
@end
  • Abra a configuração do projeto.

  • Vamos para Capabilities e habilitar Background Modes.

  • Adicionar *Background fetch e Remote Notification**.

  • Agora, execute o aplicativo. Funciona de forma semelhante à versão Android, mas o navegador Safari será aberto em vez do Chrome.

A maneira do Dart de organizar e compartilhar um conjunto de funcionalidades é por meio do Pacote. O Dart Package é simplesmente bibliotecas ou módulos compartilháveis. Em geral, o Dart Package é o mesmo do Dart Application, exceto que o Dart Package não tem o ponto de entrada do aplicativo, principal.

A estrutura geral do Pacote (considere um pacote demo, my_demo_package) é a seguinte -

  • lib/src/* - Arquivos privados de código Dart.

  • lib/my_demo_package.dart- Arquivo de código principal do DART. Ele pode ser importado para um aplicativo como -

import 'package:my_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 -

export src/my_private_code.dart
  • lib/*- Qualquer número de arquivos de código Dart organizados em qualquer estrutura de pasta personalizada. O código pode ser acessado como,

import 'package:my_demo_package/custom_folder/custom_file.dart'
  • pubspec.yaml - Especificação do projeto, a mesma 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 Dart

Código Dart genérico, que pode ser usado em ambiente web e móvel. Por exemplo, english_words é um pacote que contém cerca de 5000 palavras e tem funções utilitárias básicas como substantivos (lista de substantivos em inglês), sílabas (especifica o número de sílabas em uma palavra.

Pacote Flutter

Código Dart genérico, que depende da estrutura Flutter e pode ser usado apenas em ambiente móvel. Por exemplo, fluro é um roteador personalizado para flutter. Depende da estrutura do Flutter.

Plugin Flutter

Código Dart genérico, que depende da estrutura Flutter, bem como do código da plataforma subjacente (SDK Android ou SDK iOS). Por exemplo, a 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 de dardo

Pacotes de Dart são hospedados e publicados no servidor ao vivo, https://pub.dartlang.org.Além disso, o Flutter fornece uma ferramenta simples para gerenciar pacotes de 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 -

dependencies: english_words: ^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 -

flutter packages get
  • 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 -

import 'package:english_words/english_words.dart';
  • Use qualquer método disponível no pacote,

nouns.take(50).forEach(print);
  • Aqui, usamos a função de substantivos para obter e imprimir as 50 palavras principais.

Desenvolva um pacote de plug-in Flutter

O desenvolvimento de um plug-in Flutter é semelhante ao desenvolvimento de um aplicativo ou pacote Dart. A única exceção é que o plug-in 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. A funcionalidade do plug-in my_browser é permitir que o aplicativo abra o site fornecido no navegador específico da plataforma.

  • Inicie o Android Studio.

  • Clique File → New Flutter Project 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.

  • Insira o nome do plugin e outros detalhes na janela conforme mostrado aqui -

  • Digite o domínio da empresa, flutterplugins.tutorialspoint.com na janela mostrada abaixo e clique em Finish. Ele irá gerar um código de inicialização para desenvolver nosso novo plugin.

  • Abra o arquivo my_browser.dart e escreva um método, openBrowser, para invocar o método openBrowser específico da plataforma.

Future<void> openBrowser(String urlString) async { 
   try {
      final int result = await _channel.invokeMethod(
         'openBrowser', <String, String>{ 'url': urlString }
      );
   }
   on PlatformException catch (e) { 
      // Unable to open the browser print(e); 
   } 
}
  • Abra o arquivo MyBrowserPlugin.java e importe as seguintes classes -

import android.app.Activity; 
import android.content.Intent; 
import android.net.Uri; 
import 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.

private final Registrar mRegistrar;
  • Aqui, o Registrador é usado para obter informações de contexto do código de chamada.

  • Adicione um construtor para definir o Registrador na classe MyBrowserPlugin.

private MyBrowserPlugin(Registrar registrar) { 
   this.mRegistrar = registrar; 
}
  • Altere registerWith para incluir nosso novo construtor na classe MyBrowserPlugin.

public static void registerWith(Registrar registrar) { 
   final MethodChannel channel = new MethodChannel(registrar.messenger(), "my_browser"); 
   MyBrowserPlugin instance = new MyBrowserPlugin(registrar); 
   channel.setMethodCallHandler(instance); 
}
  • Altere onMethodCall para incluir o método openBrowser na classe MyBrowserPlugin.

@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(call, result, url); 
   } else { 
      result.notImplemented(); 
   } 
}
  • Escreva o método openBrowser específico da plataforma para acessar o navegador na classe MyBrowserPlugin.

private void openBrowser(MethodCall call, Result result, String url) { 
   Activity activity = mRegistrar.activity(); 
   if (activity == null) {
      result.error("ACTIVITY_NOT_AVAILABLE", 
      "Browser cannot be opened without foreground activity", null); 
      return; 
   } 
   Intent intent = new Intent(Intent.ACTION_VIEW); 
   intent.setData(Uri.parse(url)); 
   activity.startActivity(intent); 
   result.success((Object) true); 
}
  • O código-fonte completo do plugin my_browser é o seguinte -

my_browser.dart

import 'dart:async'; 
import 'package:flutter/services.dart'; 

class MyBrowser {
   static const MethodChannel _channel = const MethodChannel('my_browser'); 
   static Future<String> get platformVersion async { 
      final String version = await _channel.invokeMethod('getPlatformVersion'); return version; 
   } 
   Future<void> openBrowser(String urlString) async { 
      try {
         final int result = await _channel.invokeMethod(
            'openBrowser', <String, String>{'url': urlString}); 
      } 
      on PlatformException catch (e) { 
         // Unable to open the browser print(e); 
      }
   }
}

MyBrowserPlugin.java

package com.tutorialspoint.flutterplugins.my_browser; 

import io.flutter.plugin.common.MethodCall; 
import io.flutter.plugin.common.MethodChannel; 
import io.flutter.plugin.common.MethodChannel.MethodCallHandler; 
import io.flutter.plugin.common.MethodChannel.Result; 
import io.flutter.plugin.common.PluginRegistry.Registrar; 
import android.app.Activity; 
import android.content.Intent; 
import android.net.Uri; 
import android.os.Bundle; 

/** MyBrowserPlugin */ 
public class MyBrowserPlugin implements MethodCallHandler {
   private final Registrar mRegistrar; 
   private MyBrowserPlugin(Registrar registrar) { 
      this.mRegistrar = registrar; 
   } 
   /** Plugin registration. */
   public static void registerWith(Registrar registrar) {
      final MethodChannel channel = new MethodChannel(
         registrar.messenger(), "my_browser"); 
      MyBrowserPlugin instance = new MyBrowserPlugin(registrar); 
      channel.setMethodCallHandler(instance); 
   } 
   @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(call, result, url); 
      } else { 
         result.notImplemented(); 
      } 
   } 
   private void openBrowser(MethodCall call, Result result, String url) { 
      Activity activity = mRegistrar.activity(); 
      if (activity == null) {
         result.error("ACTIVITY_NOT_AVAILABLE",
            "Browser cannot be opened without foreground activity", null); 
         return; 
      }
      Intent intent = new Intent(Intent.ACTION_VIEW); 
      intent.setData(Uri.parse(url)); 
      activity.startActivity(intent); 
      result.success((Object) true); 
   } 
}
  • 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.

dependencies: 
   flutter: 
      sdk: flutter 
   my_browser: 
      path: ../my_browser
  • O Android Studio irá alertar que o pubspec.yaml é atualizado conforme mostrado no alerta do pacote do Android Studio fornecido abaixo -

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

  • Abra main.dart e inclua o plugin my_browser como abaixo -

import 'package:my_browser/my_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 -

import 'package:flutter/material.dart'; 
import 'package:my_browser/my_browser.dart'; 

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

class MyApp extends StatelessWidget { 
   @override 
   Widget build(BuildContext context) {
      return MaterialApp( 
         title: 'Flutter Demo', 
         theme: ThemeData( 
            primarySwatch: Colors.blue, 
         ), 
         home: MyHomePage(
            title: 'Flutter Demo Home Page'
         ), 
      );,
   }
} 
class MyHomePage extends StatelessWidget { 
   MyHomePage({Key key, this.title}) : super(key: key); 
   final String title; 
   @override 
   Widget build(BuildContext context) {
      return Scaffold(
         appBar: AppBar( 
            title: Text(this.title), 
         ), 
         body: Center(
            child: RaisedButton(
               child: Text('Open Browser'), 
               onPressed: () => MyBrowser().openBrowser("https://flutter.dev"), 
            ),
         ), 
      ); 
   }
}
  • Execute o aplicativo e clique no botão Abrir navegador para ver se o navegador é iniciado. Você pode ver um aplicativo de navegador - página inicial conforme mostrado na captura de tela mostrada abaixo -

Você pode ver um aplicativo de navegador - tela do navegador conforme mostrado na captura de tela mostrada abaixo -

  • Print
  •  Adicionar notas
  •  Favoritar esta página
  •  Reportar erro
  •  Suggestions

Salvar Fechar