Guia do artigo:
A todo momento surgem soluções do tipo “um código, dois aplicativos” entre as comunidades de desenvolvimento mobile. Isso é natural porque a ideia de escrever um único código que pode ser reutilizado entre aplicações e em diversas plataformas é tentadora tanto para quem financia o projeto, pela possibilidade de manter equipes menores, quanto para o desenvolvedor, que muitas vezes pode utilizar suas habilidades como ponto de partida no estudo de uma tecnologia, reduzindo assim a sua curva de aprendizado. Entretanto, muitas dessas soluções, citadas no fim, tendem a sacrificar a performance para alcançar certa onipresença.
Por exemplo, o Ionic, por executar em uma Webview, pode entregar um aplicativo multiplataforma, mas a um custo de desempenho altíssimo. O React Native, embora utilize código nativo de cada plataforma, ainda precisa de “pontes” que façam a ligação entre as mesmas e a lógica JavaScript da sua aplicação, o que também podem ser um causador de gargalos.
E se pudéssemos gerar código nativo de alto desempenho tanto para Android quanto para iOS, utilizando uma linguagem de alto nível? E se existisse uma biblioteca que nos desse todos os elementos visuais necessários para uma aplicação, seja seguindo o Material Design do Android ou o padrão de design do iOS, que permitisse a criação de aplicativos extremamente elegantes, com animações fluídas? Esse mundo existe e se chama Flutter.
O Flutter foi apresentado pela primeira vez em meados de 2017 pelo Google, mas foi em Dezembro de 2018, que a primeira versão estável foi liberada para o público. Com o Flutter podemos construir aplicativos nativos e de alta qualidade tanto para Android quanto para iOS, respeitando os padrões de cada uma dessas plataformas, a partir de um mesmo código escrito com a linguagem Dart.
Nesse artigo criaremos nosso primeiro aplicativo utilizando o Flutter. Para isso, será necessário realizar a instalação do Flutter SDK, um conjunto de ferramentas e componentes que serão utilizados para construir e compilar a aplicação. Começaremos com a configuração do Visual Studio Code, de forma a integrá-lo com o SDK e, dessa forma, seremos capazes de utilizar o recurso de Hot Reload, bem como o debugger disponibilizado pelo Flutter. Hot Reload é uma tecnologia que agiliza a depuração, diminuindo o tempo necessário para que as alterações feitas no aplicativo sejam enviadas para o dispositivo que executa a aplicação.
Instalando o Flutter SDK
O Flutter SDK pode ser utilizado no Windows, MacOS e Linux. Aqui, abordaremos apenas a instalação em ambiente Windows, mas caso você utilize outro sistema operacional e está tendo problemas para instalar o SDK, deixe um comentário que o ajudaremos. Antes de mais nada, a fim de gerarmos um APK para o Android, também precisaremos do Android SDK, que pode ser obtido pela instalação do Android Studio. Aqui na DevMedia temos um curso que ensina como preparar um ambiente de desenvolvimento Android, que cobre esse passo e pode ser utilizado como consulta, caso você precise de alguma ajuda.
Com o Android SDK instalado, podemos partir para a instalação do Flutter SDK:
- Na página de download do Flutter SDK, clique no botão “Windows”.
- Na sessão “Get the Flutter SDK”, logo abaixo dos requerimentos do sistema, clique no botão flutter_windows_v1.0.0-stable.zip.
- Na partição C:/ do seu HD, crie um diretório chamado src/ e extraia os arquivos do SDK nesse diretório:
Agora que realizamos o download do SDK, criaremos uma variável de ambiente do Windows para sermos capazes de utilizar a ferramenta de linha de comando do Flutter através do terminal do Windows:
- Na barra de busca do Windows pesquise por "Editar as variáveis de ambiente do sistema” e clique no primeiro resultado:
- Na janela que abrir, clique no botão “Variáveis de Ambiente…”:
- No campo superior, chamado “Variáveis de usuário…”, clique na variável “Path” e, então, no botão “Editar”:
- Na janela que abrir encontraremos uma lista de diretórios. Clique em “Novo” e adicione o endereço do diretório C:/src/flutter/bin do SDKe clique em “OK”:
-
Para verificar se o SDK foi instalado corretamente, abra uma sessão do CMD e execute o seguinte comando:
flutter doctor
Se tudo estiver instalado corretamente, deverá receber uma resposta similar a essa:
Doctor summary (to see all details, run flutter doctor -v): [√] Flutter (Channel beta, v1.1.8, on Microsoft Windows [versão 10.0.17134.590], locale pt-BR) [!] Android toolchain - develop for Android devices (Android SDK version 28.0.3) ! Some Android licenses not accepted. To resolve this, run: flutter doctor --android-licenses [√] Android Studio (version 3.2) [√] VS Code (version 1.31.1) [!] Connected device ! No devices available
Pronto! Agora que já possuímos o SDK, estamos prontos para configurar nossa IDE. Nesse artigo utilizaremos o Visual Studio Code, mas se quiser também pode utilizar o Android Studio (basta ter memória RAM suficiente):
- Com o Visual Studio Code aberto, no menu lateral, selecione a aba “extensões”:
- No campo de busca, digite “Flutter”. O primeiro resultado da busca será o plugin oficial. Clique no pequeno botão “Install” verde. O plugin já contém tudo que precisamos para executar e debugar nosso código Dart.
Pronto! Finalmente podemos criar nosso primeiro aplicativo em Flutter!
Criando um aplicativo com Flutter
Com o SDK instalado e adicionado à variável de ambiente “Path”, criar um novo projeto Flutter é extremamente simples. Para isso, no terminal do Windows, navegue até o diretório onde deseja iniciar o seu projeto e execute o seguinte comando:
flutter create meu_primeiro_app
O Flutter ficará encarregado de criar todos os arquivos da nossa aplicação. Feito isso, ainda no terminal, navegue até o diretório que foi criado pelo CLI:
cd meu_primeiro_app
Para abrir o projeto no Visual Studio Code basta executar o comando:
code .
Executando o aplicativo Flutter em um Emulador Android
O Android Studio, além do Android SDK, também nos fornece um emulador Android que contém todas as suas versões. Dessa forma, podemos testar o comportamento do nosso aplicativo em diversos dispositivos, ao mesmo tempo que elimina a necessidade de conectarmos um dispositivo físico para realizar testes, embora essa opção ainda seja possível.
No Visual Studio Code, abra o arquivo lib/main.dart. Ele será o ponto de entrada do nosso aplicativo, ou seja, toda aplicação será iniciada através da função main no início do arquivo. Todo o código que você vê abaixo dessa função é o aplicativo que o Flutter oferece como exemplo. Por enquanto não realizaremos nenhuma modificação, apenas executaremos este aplicativo. Para isso, com o arquivo aberto, pressione:
CRTL + F5
No topo superior do Visual Studio Code abrirá uma pequena aba. Se você já possui emuladores configurados, eles devem aparecer nessa aba. Se não, basta selecionar a opção “Create New”:
O processo deve demorar alguns minutos, e você pode acompanhá-lo através da pequena aba aberta no canto inferior direito:
Ao final do processo, quando o emulador for automaticamente aberto, pode ser que seu aplicativo não seja executado. Dessa forma, no Visual Studio Code, pressionamos “CRTL + F5” novamente. Entretanto, como o emulador já estará aberto, não será necessário escolher nenhuma opção. O Flutter ficará responsável por iniciar a aplicação no emulador e emitir todos os eventos e erros através da aba “DEBUG CONSOLE” no rodapé do Visual Studio Code:
Nesse momento, no emulador, seu aplicativo já será executado:
E é isso ai! Você acabou de entrar no mundo do desenvolvimento multiplataforma nativo. Que tal darmos uma explorada no aplicativo de exemplo que foi criado?
Widgets! Explorando um aplicativo Flutter
Tudo no Flutter é um Widget. Seja uma página, um botão ou um texto. Sempre que quisermos exibir qualquer tipo de elemento para o usuário, usaremos Widgets.
O Flutter fornece diversos Widgets que são essenciais para o funcionamento da nossa aplicação. Por isso, no arquivo main.dart onde podemos encontrar todos os elementos do nosso aplicativo de exemplo, logo na primeira linha, encontramos a importação dos Widgets do Material Design:
import 'package:flutter/material.dart';
Mais abaixo encontramos o Widget superior da aplicação. É nele, chamado de MyApp, que seremos capazes de definir um esquema de cores padrão, bem como o título e a página inicial do nosso aplicativo. Perceba também que a função main, a “porta de entrada” cria uma instância desse Widget, iniciando o aplicativo:
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'),
);
}
}
Repare que na linha 9, no parâmetro primarySwatch do construtor da classe ThemeData, passamos o valor Colors.blue. A classe Colors é fornecida pelo Flutter Material, onde encontramos diversas cores comumente utilizadas pelo Material Design. Que tal mudarmos a cor primária do nosso aplicativo para vermelho?
ThemeData(
primarySwatch: Colors.red,
),
É só salvar e, em um passe de mágica, o recurso de Hot Reload do Flutter modificará nosso aplicativo executado no emulador:
Mais abaixo encontraremos outras duas classes: MyHomePage e _MyHomePageState. Diferentemente do Widget superior da aplicação, que se tratava de um StatelessWidget (um Widget que não armazena dados), o Widget da nossa página inicial se trata de um StatefulWidget (um Widget que armazena dados e possui Lifecycle). Por isso possuímos duas classes: a primeira, chamada MyHomePage, conterá apenas os dados imutáveis do nosso Widget, ou seja, apenas os dados que forem passados como parâmetro para o Widget. É essa classe que instanciamos dentro do Widget MyApp para abrir a página inicial.
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
A segunda classe, _MyHomePageState, é onde armazenamos os dados mutáveis do componente (estado) e implementamos o método build utilizado pelo Flutter para criar o Widget na tela do usuário:
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),
),
);
}
}
Perceba que é nesse Widget que encontramos todo o código da nossa aplicação responsável por exibir o contador e, ao clique do botão de incremento, realizamos a atualização dos dados. Agora que alteramos a cor do nosso aplicativo, que tal implementar mais uma funcionalidade? Apenas um botão de incremento não é suficiente, também precisamos decrementar!
Ainda na classe _MyHomePageState criaremos mais um método chamado _decrementCounter. Este método ficará responsável por decrementar o atributo _counter da nossa aplicação e por executar o método setState disponível em todo Widget do tipo Stateful:
...
void _decrementCounter() {
setState(() {
_counter--;
});
}
...
Por fim precisaremos, no atributo floatingActionButton do Widget Scaffold, adicionar mais um botão ao lado do botão de incremento. Faremos isso agrupando ambos os botões no Widget Row, também disponibilizado pelo Flutter:
floatingActionButton: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: const Icon(Icons.add),
),
const SizedBox(
width: 10.0,
),
FloatingActionButton(
onPressed: _decrementCounter,
tooltip: 'Decrement',
child: const Icon(Icons.remove),
),
],
),
Salve as alterações e agora conseguimos mudar a cor de tema da aplicação, adicionando uma nova funcionalidade em alguns poucos passos.
Veja abaixo o código completo utilizado neste artigo.>
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.red,
),
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++;
});
}
void _decrementCounter() {
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: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: const Icon(Icons.add),
),
const SizedBox(
width: 10.0,
),
FloatingActionButton(
onPressed: _decrementCounter,
tooltip: 'Decrement',
child: const Icon(Icons.remove),
),
],
),
);
}
}
Além dos recursos apresentados aqui, o Flutter fornece centenas de Widgets, que agilizam muito o processo de desenvolvimento.