Compreendendo um aplicativo simples em Flutter
Compreendendo um aplicativo Flutter simples
Neste tutorial faremos um guia passo a passo de como criar uma aplicação Flutter simples, usando Linux como sistema operacional.
Conforme afirmado pela Google, Flutter é um framework de código aberto do Google para a construção de aplicativos multiplataforma compilados nativamente, a partir de uma única base de código. O código Flutter é compilado em código de máquina para processadores de arquitetura ARM ou Intel, bem como em JavaScript, obtendo desempenho rápido em qualquer dispositivo. Flutter é desenvolvido em Dart, uma linguagem otimizada para aplicativos rápidos em qualquer plataforma.
Aqui não entraremos em detalhes sobre a linguagem Dart, pois seus conceitos e sintaxe são facilmente compreendidos por quem está acostumado a utilizar linguagens de programação modernas, e porque nosso foco está na criação da aplicação.
Este tutorial é o primeiro de uma série que visa ensinar os principais conceitos subjacentes ao Flutter Framework por meio de exemplos simples. Em cada lição apresentaremos um exemplo completo e prático. Para isso serão mostrados exemplos funcionais, porém exibindo telas simples para que o código seja de fácil compreensão, já que nosso foco está na compreensão dos conceitos.
Neste post abordaremos os conceitos de widgets, widgets sem estado (stateless widgets) e widgets com estado (stateful widgets). Para entender esses conceitos, utilizaremos um aplicativo padrão que é apresentado na página do Flutters: o contador de cliques.
Nos próximos posts evoluiremos para uma aplicação mais complexa, que englobará chamadas de API e monetização.
A tela do aplicativo para contar cliques é mostrada abaixo.
O primeiro passo é instalar o Flutter. Siga as instruções no link abaixo para instalar de acordo com seu sistema operacional.
Depois de instalar o Flutter, execute o comando flutter doctor em um terminal para verificar se a instalação foi concluída com todas as dependências.
$ flutter doctor
Mensagens típicas de um comando flutter doctor.
Uma dependência que muitas vezes falta, como mostrado na figura acima, é o SDK do Android. Como um dos ambientes alvo é o ambiente Android, é importante que você execute a instalação. Visite o site de ferramentas do Android Studio e SDK para fazer download do Android Studio SDK. Inicie o Android Studio e siga o Assistente de configuração do Android Studio. Essa etapa instala o Android SDK, o Android SDK Command-line Tools e o Android SDK Build-Tools, que são exigidos pelo Flutter ao desenvolver para Android.
2. Configure um ambiente de desenvolvimento
Você pode desenvolver em Flutter usando um editor de código simples e executando os aplicativos desenvolvidos por meio da linha de comando. Porém, é mais produtivo usar um ambiente de desenvolvimento completo como Android Studio ou Visual code. Acesse o link abaixo para saber como fazer o download e configurar um ambiente.
Agora vamos mostrar como criar e executar nosso primeiro aplicativo flutter por meio da linha de comando.
3. Primeiro aplicativo
No diretório de sua escolha digite flutter create, seguido do nome que você escolheu para seu aplicativo. No caso do nosso exemplo, é firstapp.
$ flutter create firstapp
Este comando criará um diretório contendo toda a estrutura de um projeto flutter, incluindo um arquivo main.dart, no subdiretório lib que contém o código do aplicativo na linguagem dart.
Estrutura do projeto criado.
Depois de criar o aplicativo, você pode executá-lo acessando o diretório do aplicativo e executando o comando flutter run.
$ cd firstapp
$ flutter run
Se você tiver um smartphone conectado ao computador, o aplicativo será executado no dispositivo. Caso contrário, o framework apresentará opções de execução, conforme mostrado na tela.
A executar a aplicação, cada vez que o botão exibido no canto inferior direito é pressionado, o valor do número exibido é incrementado em um. É uma primeira aplicação interessante porque apresenta uma interação que a distingue das primeiras aplicações clássicas como Hello World. Vamos agora examinar o código para entender como ele funciona.
Neste primeiro trecho de código, do arquivo main.dart, podemos ver o ponto inicial da execução, que é a função main .
A função main invoca a função run App, passando como parâmetro uma instância de uma classe que de fato descreve a interface que será exibida. No caso do nosso exemplo, é uma instância da classe MyApp. O corpo da função principal é implementado usando a notação de seta, que é uma notação mais enxuta para definir funções que possuem um corpo simples.
A classe que descreve a interface é uma subclasse de Widget. Um Widget é um componente de uma interface que permite ao usuário executar uma função ou acessar um serviço. No caso do flutter existem dois tipos de widgets: o Stateless Widget e o Stateful Widget .
O Stateless Widget é um componente que não possui um estado mutável e, portanto, não precisa monitorar uma mudança de estado que possa afetar sua exibição.
Por outro lado, um Stateful Widget é um componente que possui um estado interno, e as mudanças no estado precisam ser monitoradas, pois afetam sua aparência e a forma como interage.
Flutter fornece uma biblioteca de widgets básicos que podem ser combinados, formando uma árvore de componentes que descrevem uma interface complexa. Os widgets que abrigam outros widgets são chamados de contêineres (containers).
Voltando ao código, podemos ver que o Widget possui um parâmetro key que pode ser encontrado basicamente em todos os construtores de widget. As keys preservam o estado quando os widgets se movem na árvore de widgets. Na prática, isso significa que elas podem ser úteis para preservar a localização de rolagem do usuário ou manter o estado ao modificar uma coleção. Como a variável pode ter valor nulo , ela é declarada com um ponto de interrogação.
Uma subclasse da classe do widget deve implementar um método build que defina como o widget será renderizado e retornando a subárvore do widget que foi criada deste ponto em diante.
Este método recebe uma instância de um build context object como argumento. Esta instância contém informações sobre a posição do widget na árvore em tempo de execução. Ou seja, seus pais e filhos. Portanto, cada contexto de construção possui informações diferentes para cada widget.
O método retorna um widget Material App. É chamado de material app porque utiliza Material Design, que é uma linguagem de design desenvolvida pelo Google em 2014, e hoje é uma das maiores tendências do design. Material App é um widget conveniente que agrupa vários widgets comumente necessários para aplicativos de material design. Neste exemplo estamos definindo o título da aplicação, seu tema que é a cor azul, e um widget filho através da propriedade home, que será a primeira tela a ser mostrada na aplicação. Em nosso exemplo, é um widget com estado chamado myHomePage, mas pode ter qualquer nome que você desejar.
Outra característica interessante do Flutter é o fato de permitir que alterações de código sejam exibidas sem a necessidade de reiniciar o aplicativo. Esse recurso é chamado de hot reload, e é um recurso que acelera bastante o processo de desenvolvimento.
Vamos ver como isso funciona.
altere a propriedade primarySwatch para Colors.green e, em seguida, invoque “hot reload” pressionando “r” no console onde você digitou flutter run ou simplesmente salve suas alterações em um Flutter IDE para que ocorra o “hot reload”. Observe que o contador não foi zerado; o aplicativo não é reiniciado.
Vamos agora examinar o código da classe Myhomepage.
A classe MyHomePage é uma subclasse de StatefulWidget, o que significa que possui um objeto State que contém campos que afetam sua aparência. Esta classe é a configuração do estado. Ele contém os valores, neste caso o título, fornecidos pelo pai e usados pelo método de build do Estado. Os campos em uma subclasse Widget são sempre marcados como final.
Na verdade, quem cuida do estado e da renderização é o objeto State que deve ser criado sobrescrevendo o método create state. Vamos então examinar a implementação da classe deste objeto.
O Dart usa um underline inicial em um identificador para marcar membros e declarações de nível superior como privados (private). Como esta classe será usada apenas no escopo do Widget, faz sentido marcá-la como private. Nesta classe são declaradas as variáveis que armazenam as informações de estado do widget. No caso deste exemplo, temos a variável _counter que também é declarada como privada. Ele armazena o número de vezes que o botão da tela foi pressionado.
Quando a variável tem seu valor alterado, o framework deve ser informado para re-renderizar o widget para refletir a mudança. Isso é feito chamando o método setState. Chamar setState notifica que o estado interno deste objeto mudou de uma forma que pode impactar a interface do usuário nesta subárvore, o que faz com que o framework agende uma reconstrução para este objeto State.
Neste exemplo, o método é chamado dentro do método privado _incrementCounter, e dentro do método setState, a variável _counter é incrementada em um. Se alterássemos _counter sem chamar setState, o método build não seria chamado novamente e, portanto, nada aconteceria. Este estilo de programação de UI é chamado de frameworks de UI declarativos, em oposição ao estilo imperativo de programação de UI.
No estilo imperativo , o programador é responsável por definir o controle da interface, coletando as interações do usuário e as alterações no modelo e, a partir daí, realizar as alterações apropriadas na interface.
No estilo declarativo , o programador só precisa informar que o estado mudou, e o framework é responsável por fazer alterações na interface, para refletir essas alterações, e apenas nos elementos afetados.
Isto alivia consideravelmente a carga de trabalho do programador e diminui a chance de erros. No estilo declarativo, as configurações de visualização, como os Widgets do Flutter, são imutáveis e são apenas “projetos” leves. Para alterar a IU, um widget aciona uma reconstrução em si mesmo e constrói uma nova subárvore de widget .
Como já mencionado, um widget precisa fornecer um método build que define como a subárvore será construída. No caso do nosso exemplo, o método retorna um scaffold widget. O widget Scaffold implementa a estrutura de layout visual básica do Material Design e permite definir outros widgets do Material Design dentro dela. O widget Scaffold geralmente é suficiente para criar um aplicativo móvel de uso geral e contém quase tudo que você precisa para criar um aplicativo funcional e responsivo.
Este widget é capaz de ocupar toda a tela do dispositivo, sendo o principal responsável por criar uma base para a tela do aplicativo na qual os widgets filhos ficam presos e renderizados na tela. Ele fornece muitos widgets ou APIs: Drawer, Snack Bar, Bottom Navigation Bar, App Bar, Floating Action Button e muito mais.
Neste exemplo definiremos apenas a appbar e o body do aplicativo.
Na barra de aplicativos exibimos o título do aplicativo .
No body são colocados dois widgets, um contêiner central de widgets que centraliza seus widgets filhos e um widget flutuanteActionButton que pode ser clicado pelo usuário. Eles estão empilhados um em cima do outro. No centro do widget, outro contêiner é inserido, que é um widget Column.
No widget Column, dois widgets Text são inseridos. Um dos widgets Text será usado para exibir o número de cliques no botão. Observe o símbolo '$' usado na string literal. Esse símbolo é usado quando você deseja obter o valor de uma expressão usada dentro de uma string literal.
Neste caso, queremos exibir o valor contido na variável _counter. Observe também a utilização da variável context para obter o estilo que deve ser utilizado no texto, de acordo com o tema da aplicação.
O outro widget inserido no corpo do scaffold é um floatActionButton. Quando pressionado, ele invoca o método _incrementCounter, que por sua vez invoca o método setState, fazendo com que o widget seja renderizado novamente. ThefloatingActionButton possui um widget filho que é um Icon do sinal "+" .
A árvore completa de widgets para este aplicativo simples é a seguinte.
As dependências do aplicativo são declaradas em um arquivo chamado pubspec.yaml. O arquivo é escrito na linguagem YAML, também conhecida como YAML Ain't Markup Language. YAML é uma linguagem de serialização de dados para todas as linguagens de programação. Aqui podemos ver os campos obrigatórios para esta aplicação.
pubspec.yaml
Dependendo do ambiente de destino, haverá arquivos de configuração para cada ambiente. Aqui podemos ver o arquivo de configuração para ambiente Android .
AndroidManifest.xml
O código completo é mostrado abaixo.
import 'package:flutter/material.dart'; void main() => runApp(const MyApp()); class MyApp extends StatelessWidget { const MyApp({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', theme: ThemeData( primarySwatch: Colors.blue, ), home: const MyHomePage(title: 'Flutter Demo Home Page'), ); } } class MyHomePage extends StatefulWidget { const MyHomePage({Key? key, required this.title}) : super(key: key); final String title; @override State<MyHomePage> createState() => _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> { int _counter = 0; void _incrementCounter() { setState(() { _counter++; }); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ const Text( 'You have pushed the button this many times:', ), Text( '$_counter', style: Theme.of(context).textTheme.headline4, ), ], ), ), floatingActionButton: FloatingActionButton( onPressed: _incrementCounter, tooltip: 'Increment', child: const Icon(Icons.add), ), // This trailing comma makes auto-formatting nicer for build methods. ); } }
Chegamos ao final desta lição. Obrigado pela leitura e espero que tenha sido útil.
Comentários
Postar um comentário