Flutter: O Guia Definitivo
Escreva um código, rode em todo lugar. Domine a árvore de Widgets, o Dart e a engine gráfica que revolucionou o desenvolvimento mobile.
1. Introdução: A Revolução do Flutter
O desenvolvimento mobile viveu por anos um dilema: ou você gastava o dobro para criar dois apps nativos (Swift para iOS e Kotlin para Android), ou criava um app híbrido lento que parecia um site rodando no celular.
O Flutter chegou para quebrar essa barreira, oferecendo o "Santo Graal" do desenvolvimento: performance nativa real com um único código para todas as plataformas.
1.1. O que é o Flutter? (Definição Técnica)
Ao contrário do que muitos pensam, o Flutter não é apenas um "framework". Ele é um UI Toolkit (Kit de Ferramentas de Interface) completo, criado e mantido pelo Google.
Ele permite criar aplicações compiladas nativamente para:
- 📱 Mobile: Android e iOS.
- 💻 Desktop: Windows, macOS e Linux.
- 🌐 Web: Sites e PWAs.
- 📟 Embedded: Carros, geladeiras inteligentes, etc.
Tudo isso usando uma única base de código escrita na linguagem Dart.
1.2. Como o Flutter Funciona? (A Mágica da Engine)
Aqui está o grande diferencial. A maioria das ferramentas híbridas (como React Native ou Ionic) usa os componentes do próprio celular. Elas dizem ao sistema: "Por favor, desenhe um botão do Android aqui".
O Flutter faz diferente. Ele ignora os botões do sistema. Ele pede ao sistema operacional apenas uma coisa: uma tela em branco (Canvas).
- A Engine Gráfica (Impeller/Skia): O Flutter traz seu próprio motor de renderização (o mesmo usado no Google Chrome). Ele desenha cada pixel, cada sombra e cada texto manualmente.
- Controle Total: Como é o Flutter quem desenha, o app fica idêntico em qualquer dispositivo. Um botão criado no Flutter terá exatamente a mesma aparência em um iPhone antigo ou num Android novo, pixel por pixel.
1.3. Como utilizamos o Flutter?
O desenvolvimento em Flutter é baseado em três pilares principais que você precisa dominar:
- Linguagem Dart: Uma linguagem moderna, otimizada para UI, que combina o melhor do Java e do JavaScript. Ela é fácil de aprender e fortemente tipada.
- UI Declarativa: Você não manipula a tela manualmente. Você declara: "Se o usuário estiver logado, mostre a Home. Se não, mostre o Login". O Flutter cuida da transição.
- Hot Reload: A ferramenta mais amada pelos devs. Você altera a cor de um botão, salva o arquivo e a mudança aparece no celular em menos de 1 segundo, sem reiniciar o app e sem perder o estado (o que você digitou no formulário continua lá).
1.4. Por que Flutter e não React Native? (O Comparativo)
Essa é a dúvida clássica. Ambos são excelentes, mas possuem arquiteturas opostas.
| Característica | React Native (JS) | Flutter (Dart) |
|---|---|---|
| Arquitetura | Usa uma "Ponte" (Bridge) para conversar com o nativo. O JS manda mensagens para o celular desenhar a tela. | Sem Ponte. O código é compilado direto para linguagem de máquina (ARM/x86). |
| Performance | Boa, mas pode engasgar em animações complexas devido ao tráfego na "Ponte". | Excelente (60/120 FPS). Performance próxima do Nativo puro. |
| Visual | Usa componentes nativos (o app muda de cara se o iOS atualizar). | Usa componentes próprios (o app mantém sua identidade visual sempre). |
| Estabilidade | Depende de bibliotecas de terceiros para quase tudo. | Vem com uma biblioteca gigante de Widgets oficiais do Google "baterias inclusas". |
Resumo: Escolha Flutter se você quer performance máxima, controle visual total (pixel-perfect) e não quer depender de componentes do sistema que podem mudar numa atualização do Android/iOS.
2. A Alma do Negócio: Linguagem Dart
O Flutter é o carro, mas o Dart é o motor. Muitos iniciantes perguntam: "Por que eu tenho que aprender Dart? Por que não usaram JavaScript?".
A resposta curta é: Performance. O Dart foi projetado especificamente para construir interfaces (Client-Side) rápidas, corrigindo os problemas de lentidão do JavaScript e a verbosidade do Java.
2.1. O que é o Dart?
Criado pelo Google em 2011, o Dart é uma linguagem orientada a objetos, fortemente tipada e focada em "Desenvolvimento de UI".
Pense nele como o filho perfeito entre o Java e o JavaScript:
- Do Java, ele herdou a segurança, a tipagem forte e a orientação a objetos.
- Do JavaScript, ele herdou a sintaxe moderna, as arrow functions
() =>e a flexibilidade.
Se você já programou em C#, Swift ou TS, você já sabe 90% de Dart sem saber.
2.2. Como o Dart Funciona? (O Segredo JIT vs AOT)
Esta é a parte técnica mais importante. O Dart possui dois modos de compilação, e ele troca de roupa dependendo do momento.
Modo 1: Desenvolvimento (JIT - Just In Time)
Quando você está codando, o Dart usa uma Máquina Virtual (VM).
- Como funciona: Ele lê e executa o código na hora, sem compilar tudo antes.
- O Benefício: Isso permite o famoso Hot Reload. Você muda uma cor, salva, e a VM injeta apenas aquele pedaço de código novo no app rodando, atualizando a tela em milissegundos.
Modo 2: Produção (AOT - Ahead Of Time)
Quando você vai publicar o App na loja, o Dart muda de estratégia.
- Como funciona: Ele compila todo o seu código para Linguagem de Máquina Nativa (Binário ARM/x86).
- O Benefício: O app final não precisa de uma "ponte" ou interpretador JS. Ele roda direto no processador do celular, garantindo inicialização instantânea e animações suaves.
2.3. Como utilizamos o Dart? (Sintaxe Moderna)
O Dart moderno (versão 3+) foca muito em segurança contra erros nulos (Null Safety). Veja os conceitos chave:
Variáveis e Tipagem
void main() {
// Inferência de Tipo (O Dart sabe que é String)
var nome = "Flutter";
// Tipagem Explícita
int idade = 30;
// Constantes (Imutáveis)
final dataHoje = DateTime.now(); // Definido em tempo de execução
const pi = 3.14; // Definido em tempo de compilação
print('Olá, $nome! Você tem $idade anos.');
}
O Poder do Null Safety (Segurança Nula)
O Dart impede que você use valores vazios (null) por acidente, acabando com o erro mais comum da programação ("NullPointerException").
// ❌ Erro: Uma String normal NÃO pode ser nula
String nome = null;
// ✅ Correto: O '?' diz que pode ser nulo
String? apelido = null;
// ✅ Uso Seguro: O Dart te obriga a verificar
if (apelido != null) {
print(apelido.toUpperCase());
}
2.4. Por que Dart e não JavaScript/Kotlin?
O Google tinha dezenas de linguagens à disposição. A escolha do Dart foi estratégica por 3 motivos que outras linguagens não conseguiam atender simultaneamente:
| Linguagem | O Problema para UI |
|---|---|
| JavaScript | É interpretado (lento) ou precisa de uma "Ponte" (React Native). Não tem tipagem forte nativa (precisa de TS). |
| Java / Kotlin | São ótimos, mas a compilação é lenta (JIT limitado). O ciclo de "escrever código -> ver na tela" demora muito. |
| Dart (A Solução) |
1. Coleta de Lixo (Garbage Collector): O Dart é otimizado para destruir milhares de widgets por segundo (animações) sem travar o app. 2. Layout Declarativo: A sintaxe do Dart foi moldada para criar estruturas de árvore (Widgets) de forma legível, sem precisar de arquivos XML ou JSX separados. |
Resumo: O Dart não foi escolhido por ser "popular", mas por ser a única ferramenta capaz de oferecer Hot Reload (produtividade) e Código Nativo (performance) na mesma linguagem.
3. A Filosofia: "Tudo é um Widget"
No desenvolvimento Web tradicional, você separa as coisas: HTML para estrutura, CSS para estilo e JS para lógica. No Flutter, essa barreira não existe.
Tudo é um Widget. O botão é um Widget. O texto é um Widget. Mas a parte que explode a mente é: o alinhamento, o espaçamento e a cor também são Widgets.
3.1. O que é um Widget? (O DNA da UI)
Tecnicamente, um Widget é uma descrição imutável de uma parte da interface. Pense neles como "Plantas de Arquitetura" ou "Receitas de Bolo".
Eles não são o elemento final desenhado na tela (quem faz isso é um objeto pesado chamado RenderObject), eles são apenas configurações leves e baratas.
- Visual: Botões, Textos, Imagens, Ícones.
- Layout: Linhas (Row), Colunas (Column), Centralização (Center).
- Interativo: Detector de toques (GestureDetector), InkWell.
3.2. Como o Widget Funciona? (Composição vs Herança)
A maioria das linguagens antigas usa Herança (um "BotãoVermelho" herda de "Botão"). O Flutter usa Composição.
Imagine que você está brincando de Lego.
- Você não "pinta" um bloco de Lego. Você pega um bloco azul e encaixa em cima de um bloco cinza.
- No Flutter: Se você quer um texto com margem (padding), você não adiciona uma propriedade
margin. Você pega o widgetTexte o "embrulha" dentro de um widgetPadding.
// O jeito Flutter de pensar (Composição)
Padding(
padding: EdgeInsets.all(20), // O Pai define o espaçamento
child: Container( // O Filho é o conteúdo
color: Colors.blue,
child: Text("Olá Mundo"), // O Neto é o texto
),
)
3.3. Como utilizamos? (A Árvore de Widgets)
Como "um coloca o outro dentro", acabamos criando uma estrutura hierárquica chamada Widget Tree (Árvore de Widgets).
Existem duas propriedades mágicas que você usará 99% do tempo para conectar essas peças:
A) child (Filho Único)
Usado quando o widget só pode ter um item dentro dele (ex: Container, Center, SizedBox).
Center(
child: Text("Estou sozinho no centro"),
)
B) children (Múltiplos Filhos)
Usado quando o widget organiza uma lista de itens (ex: Column, Row, ListView).
Column(
children: [
Text("Primeiro item"),
Text("Segundo item"),
Text("Terceiro item"),
],
)
3.4. Por que Widgets e não HTML+CSS?
Pode parecer estranho misturar estrutura e estilo no começo, mas essa abordagem resolveu o maior pesadelo do desenvolvimento Web: a inconsistência.
| Abordagem Web (HTML/CSS) | Abordagem Flutter (Widgets) |
|---|---|
Fragmentado: Você cria uma <div> no HTML e tem que ir em outro arquivo CSS criar uma classe para centralizá-la. |
Unificado: Você apenas envolve seu componente num widget Center. O layout está explícito no código. |
| Contexto Confuso: "Por que minha margem não funciona?". Muitas vezes regras de CSS conflitam entre si (cascata). | Isolamento: Como cada Widget cuida do seu próprio "quadrado", o estilo de um botão nunca quebra o layout do cabeçalho. |
| Mutável (Lento): O navegador tenta recalcular o layout da página inteira quando algo muda. | Imutável (Rápido): Se um Widget muda, o Flutter o substitui instantaneamente por um novo, sem afetar o resto da árvore. |
A Regra Mental:
Sempre que você pensar "Como eu coloco uma borda nisso?" ou "Como eu movo isso para a direita?", a resposta nunca é uma propriedade. A resposta é: "Qual Widget faz isso?".
4. O Coração do Flutter: Gerenciamento de Estado
No Flutter, a interface do usuário (UI) não é fixa. Ela é uma função do seu Estado. A fórmula mágica é: UI = f(Estado).
Para controlar isso, o Flutter divide o mundo em dois tipos de Widgets. Saber escolher entre eles é a decisão mais importante que você fará ao criar uma tela.
4.1. StatelessWidget (A Fotografia)
O que é?
O StatelessWidget (Widget Sem Estado) é um componente imutável. Ele é como uma fotografia impressa ou uma estátua de mármore. Uma vez que ele é desenhado na tela, ele não pode mudar sua própria aparência internamente.
Como funciona?
Ele é "burro" (no bom sentido). Ele apenas recebe dados do seu pai (via construtor) e os exibe. Ele não guarda memória. Se você quiser mudar o texto de um StatelessWidget, você precisa destruí-lo e criar um novo no lugar.
Como utilizamos?
Usamos para partes da tela que são estáticas ou que apenas exibem informações fixas.
// Exemplo: Um cartão de boas-vindas
// Ele sempre mostrará o texto que recebeu, sem mudar sozinho.
class CartaoBoasVindas extends StatelessWidget {
final String nome;
CartaoBoasVindas({required this.nome});
@override
Widget build(BuildContext context) {
return Text("Olá, $nome!");
}
}
Por que utilizamos? (Vantagens)
Performance Pura. Como ele não precisa vigiar variáveis nem detectar mudanças, o Flutter consegue desenhá-lo extremamente rápido. Em um App profissional, tente fazer 90% dos seus widgets serem Stateless.
4.2. StatefulWidget (O Filme)
O que é?
O StatefulWidget (Widget Com Estado) é um componente vivo e dinâmico. Ele é como um vídeo ou um relógio digital. Ele possui uma "memória interna" (State) que pode mudar enquanto o usuário olha para a tela.
Como funciona? (O Truque das Duas Classes)
Diferente do Stateless, o Stateful é formado por duas classes conectadas:
- O Widget (A Capa): É imutável e pública. Contém apenas as configurações iniciais.
- O State (O Cérebro): É mutável e privada. É aqui que as variáveis (como um contador) vivem. Essa classe sobrevive mesmo quando o Flutter redesenha a tela.
Como utilizamos?
Usamos sempre que precisamos de interação: formulários onde o usuário digita, checkboxes, animações ou dados que vêm da internet.
Por que utilizamos?
Porque ele nos dá acesso ao método mágico setState(). Sem ele, o app seria estático. É a única forma de dizer ao Flutter: "Ei, essa variável mudou, pinta a tela de novo!".
4.3. O Grande Duelo: Comparativo Detalhado
Ainda confuso? Veja a comparação lado a lado.
| Característica | StatelessWidget | StatefulWidget |
|---|---|---|
| Mutabilidade | Totalmente Imutável (Static). | Mutável (Dynamic). |
| Renderização | Desenhado apenas uma vez (ou quando o pai muda). | Pode se redesenhar quantas vezes quiser (via setState). |
| Custo (Performance) | Baixo (Leve). | Médio (Precisa alocar memória para o Estado). |
| Exemplo da Vida Real | Um Cartaz na parede. | Uma TV ligada passando notícias. |
4.4. Tutorial Prático: Aplicando os Conceitos
Vamos ver na prática como transformar um no outro. Vamos criar um botão de "Like" (Curtir).
Cenário 1: O Botão Morto (Stateless)
Se fizermos assim, o botão nunca vai mudar de cor, não importa o quanto você clique.
class BotaoLikeMorto extends StatelessWidget {
@override
Widget build(BuildContext context) {
return IconButton(
icon: Icon(Icons.favorite_border),
onPressed: () {
// Você pode clicar, mas nada visual acontece aqui
// porque este Widget não tem "memória" para saber que foi clicado.
print("Cliquei, mas não mudei!");
},
);
}
}
Cenário 2: O Botão Vivo (Stateful - Passo a Passo)
Agora vamos dar vida a ele.
Passo 1: Definir a estrutura (Atalho: digite 'stful' no VS Code)
class BotaoLikeVivo extends StatefulWidget {
@override
_BotaoLikeVivoState createState() => _BotaoLikeVivoState();
}
Passo 2: Criar a Lógica e a UI
class _BotaoLikeVivoState extends State<BotaoLikeVivo> {
// 1. A Memória (Estado)
bool estaCurtido = false;
@override
Widget build(BuildContext context) {
return IconButton(
// 2. A UI reage ao Estado
// Se 'estaCurtido' for true, ícone cheio. Se false, borda.
icon: Icon(estaCurtido ? Icons.favorite : Icons.favorite_border),
color: estaCurtido ? Colors.red : Colors.grey,
// 3. A Interação
onPressed: () {
// 4. A Mágica (setState)
setState(() {
estaCurtido = !estaCurtido; // Inverte o valor
});
},
);
}
}
Dica de Arquiteto:
Uma boa prática é tentar manter os Widgets nas pontas da árvore (botões, textos, itens de lista) como Stateless. Deixe o Stateful apenas para o Widget "Pai" que gerencia a tela. Isso deixa o código mais limpo e rápido.
5. Mão na Massa: Configurando e Criando
Antes de colarmos aquele código do contador, precisamos preparar o terreno. O Flutter não é um programa único que você instala e abre. Ele é um ecossistema.
5.1. O Ambiente de Desenvolvimento (O Setup)
Para programar em Flutter, você precisa de 3 peças fundamentais trabalhando juntas:
- Flutter SDK: O kit de ferramentas (o compilador Dart, as bibliotecas).
- Android Studio (As Ferramentas): Você NÃO precisa escrever código nele, mas é OBRIGATÓRIO tê-lo instalado. Por quê? Porque ele traz o Android SDK e o Emulador (o celular virtual).
- VS Code (O Editor): É onde vamos escrever o código. É leve, rápido e tem ótimos plugins para Flutter.
Passo a Passo da Instalação:
C:\src\flutter). Não coloque em "Arquivos de Programas" (precisa de permissão de adm).2. Instale o Android Studio: Baixe no site oficial. Durante a instalação, marque a opção "Android Virtual Device".
3. Prepare o VS Code: Abra o VS Code e instale a extensão oficial chamada "Flutter" (ela instala a do Dart automaticamente).
4. O Diagnóstico (Flutter Doctor): Abra seu terminal e digite
flutter doctor. Ele vai te dizer exatamente o que falta (ex: aceitar licenças do Android). Siga o que ele mandar.
5.2. Criando o Projeto
Com tudo instalado, abra o VS Code.
- Abra o terminal integrado (`Ctrl + '`).
- Digite:
flutter create contador_app. - Entre na pasta:
cd contador_app. - Na pasta
lib, você verá o arquivomain.dart. É aqui que a mágica acontece. Apague tudo o que está lá e cole o código abaixo.
5.3. O Código Explicado (Anatomia do App)
Vamos entender a arquitetura por trás de cada bloco.
// 1. IMPORTAÇÃO
// Traz a caixa de ferramentas de UI do Google (Material Design)
import 'package:flutter/material.dart';
// 2. PONTO DE PARTIDA
// Todo app começa na função main(). O runApp diz: "Infle esse widget na tela".
void main() {
runApp(MeuApp());
}
// 3. A CONFIGURAÇÃO INICIAL (Stateless)
// Este Widget apenas configura o tema e chama a primeira página.
class MeuApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Contador',
theme: ThemeData(primarySwatch: Colors.blue),
home: ContadorPage(), // <--- Aponta para a tela real
);
}
}
// 4. A TELA INTERATIVA (Stateful)
// Lembra? Se a tela muda (o número cresce), ela precisa ser Stateful.
class ContadorPage extends StatefulWidget {
@override
_ContadorPageState createState() => _ContadorPageState();
}
// 5. O CÉREBRO DA TELA (State)
// Onde a lógica e o visual se encontram.
class _ContadorPageState extends State<ContadorPage> {
// A. A Variável de Estado
int contador = 0;
// B. A Função de Ação
void incrementar() {
// setState é o GATILHO. Sem ele, a variável muda, mas a tela não.
setState(() {
contador++;
});
}
// C. O Desenho da Tela (Build)
@override
Widget build(BuildContext context) {
// Scaffold é o "Esqueleto" padrão de um App (Barra, Corpo, Botão)
return Scaffold(
appBar: AppBar(title: Text("Meu Contador")),
// O corpo centraliza tudo
body: Center(
// Coluna empilha itens verticalmente
child: Column(
mainAxisAlignment: MainAxisAlignment.center, // Centraliza na vertical
children: [
Text("Você clicou:", style: TextStyle(fontSize: 20)),
// O texto que exibe a variável
Text(
"$contador",
style: TextStyle(fontSize: 40, fontWeight: FontWeight.bold)
),
],
),
),
// O Botão Flutuante
floatingActionButton: FloatingActionButton(
onPressed: incrementar, // Liga o clique à função
child: Icon(Icons.add),
),
);
}
}
5.4. Como Rodar o App (Run)
Você não precisa de linha de comando para isso. O VS Code facilita sua vida.
- No canto inferior direito do VS Code, clique onde diz "No Device" (ou Windows/Linux).
- Selecione um emulador (se criou um no Android Studio) ou conecte seu celular via USB.
- Aperte F5 no teclado.
Aguarde alguns instantes (a primeira vez demora) e voilà! Seu contador estará rodando. Tente mudar a cor do Colors.blue para Colors.green no código e salve (Ctrl+S). Veja o Hot Reload acontecer instantaneamente.
6. A Engenharia do Layout: Row e Column
No Flutter, layout é geometria. Quase tudo o que você vê na tela é uma caixa dentro da outra.
Para organizar essas caixas, usamos dois Widgets fundamentais que funcionam como o "Flexbox" do desenvolvimento Web, mas muito mais previsíveis.
6.1. O Conceito dos Eixos (A Regra de Ouro)
Para usar esses widgets, você precisa dominar o sistema de coordenadas. Cada um tem um Eixo Principal (onde ele corre) e um Eixo Cruzado (o sentido contrário).
| Widget | Direção (Main Axis) | Alinhamento Secundário (Cross Axis) |
|---|---|---|
| Row (Linha) | Horizontal (➡) | Vertical (⬆⬇) |
| Column (Coluna) | Vertical (⬇) | Horizontal (⬅➡) |
6.2. Column (A Pilha Vertical)
É o widget mais comum. Ele empilha elementos de cima para baixo.
Cenário de Uso: Uma tela de login (Logo, Input de Email, Input de Senha, Botão Entrar). Todos um embaixo do outro.
Column(
// Alinha tudo no CENTRO da tela (Verticalmente)
mainAxisAlignment: MainAxisAlignment.center,
// Estica os itens para ocupar a largura toda (Horizontalmente)
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text("Bem-vindo"),
Icon(Icons.login),
ElevatedButton(onPressed: () {}, child: Text("Entrar"))
],
)
6.3. Row (A Lista Horizontal)
Coloca elementos lado a lado.
Cenário de Uso: Um item de lista com ícone e texto, ou botões de "Sim" e "Não" lado a lado.
Row(
// Espalha os itens (Um na ponta esquerda, outro na direita)
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text("Preço Total:"),
Text("R$ 50,00", style: TextStyle(fontWeight: FontWeight.bold)),
],
)
6.4. Tutorial Passo a Passo: Card de Rede Social
O segredo do layout profissional é aninhar linhas dentro de colunas. Vamos criar um card estilo "Instagram".
A Lógica Visual:
- O Card inteiro é uma Coluna (Cabeçalho em cima da Imagem, em cima do Rodapé).
- O Cabeçalho é uma Linha (Foto de perfil ao lado do Nome).
- O Rodapé é uma Linha (Ícone de Coração ao lado do ícone de Comentário).
Container(
padding: EdgeInsets.all(10),
color: Colors.white,
// 1. A Coluna Principal
child: Column(
crossAxisAlignment: CrossAxisAlignment.start, // Alinha tudo à esquerda
children: [
// 2. O Cabeçalho (Linha)
Row(
children: [
CircleAvatar(child: Icon(Icons.person)), // Avatar
SizedBox(width: 10), // Espaçamento invisível (Dica Pro!)
Text("Maria Silva", style: TextStyle(fontWeight: FontWeight.bold)),
],
),
SizedBox(height: 10), // Espaço vertical
// 3. A Imagem (Item da Coluna)
Container(
height: 200,
color: Colors.grey[300],
child: Center(child: Text("Foto da Postagem")),
),
SizedBox(height: 10),
// 4. O Rodapé (Linha de Ações)
Row(
children: [
Icon(Icons.favorite_border),
SizedBox(width: 15),
Icon(Icons.chat_bubble_outline),
Spacer(), // Empurra o próximo item para o final da linha
Icon(Icons.bookmark_border),
],
)
],
),
)
6.5. Dicas de Ouro para ser Prático
- SizedBox é vida: Pare de tentar colocar
marginem tudo. Quer separar dois textos? Coloque umSizedBox(height: 10)entre eles. É mais legível. - O Erro da Faixa Amarela: Se o conteúdo da Row for maior que a tela, vai aparecer uma faixa de "Overflow" amarela e preta. Para corrigir, envolva o texto longo em um widget
ExpandedouFlexible. - Expanded: Use dentro de Row ou Column para dizer "Ocupe todo o espaço que sobrar". É vital para layouts responsivos.
Truque do VS Code:
Não escreva a árvore manualmente. Escreva o Widget filho (ex:Text), clique nele com o botão direito (ou Ctrl + .) e escolha "Wrap with Column" ou "Wrap with Row". O editor faz o aninhamento para você.
7. O Próximo Nível: Onde você pode chegar?
Sendo bem sincero com você: na primeira vez que a gente olha aquela "escada" de códigos do Flutter (Center dentro de Column dentro de Scaffold), dá um nó na cabeça. Parece bagunçado, parece que sobra parênteses no final. É normal sentir isso.
Mas a virada de chave acontece quando você salva o arquivo e vê o App mudar no seu celular em menos de 1 segundo. A produtividade que o Flutter te dá é viciante. Você para de "lutar" contra o layout e começa a se divertir criando ele.
Você não está apenas aprendendo a fazer "telinhas". Você está dominando uma tecnologia que te permite entregar valor para iOS, Android, Web e Desktop com o mesmo esforço. Isso é um superpoder no mercado atual.
Sobre o Desafio Final (A Solução)
Eu te desafiei a colocar um botão de "Diminuir" ao lado do botão de "Aumentar".
Se você tentou apenas jogar outro FloatingActionButton embaixo, viu que deu erro, certo? Isso acontece porque o parâmetro floatingActionButton espera receber um único Widget.
O Segredo: Para ter dois botões, você precisa "enganar" o sistema. Você entrega um único Widget (uma Row) e, dentro dessa linha, você coloca os dois botões.
🛠️ Ver o Gabarito (Código Funcionando)
Aqui está o truque da Row com MainAxisSize.min (para a linha não ocupar a tela toda):
// Dentro da sua classe _ContadorPageState:
// 1. Crie a função de diminuir
void diminuir() {
setState(() {
if (contador > 0) { // Opcional: Para não ficar negativo
contador--;
}
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Contador Evolution")),
body: Center(
child: Text(
"$contador",
style: TextStyle(fontSize: 50, fontWeight: FontWeight.bold)
),
),
// 2. O Truque da Linha
floatingActionButton: Row(
mainAxisAlignment: MainAxisAlignment.end, // Alinha à direita
mainAxisSize: MainAxisSize.min, // "Ocupe só o espaço necessário"
children: [
// Botão Menos
FloatingActionButton(
onPressed: diminuir,
backgroundColor: Colors.red, // Diferenciar a cor
child: Icon(Icons.remove),
),
SizedBox(width: 15), // Um respiro entre os botões
// Botão Mais
FloatingActionButton(
onPressed: incrementar,
child: Icon(Icons.add),
),
],
),
);
}
Agora o controle está com você. O Flutter é vasto, mas você já tem a fundação: Widgets, Layouts e Estado. O próximo passo? Tente consumir uma API real (como a de pokémons ou de clima) e exibir na tela. É errando e consertando que a gente vira sênior. Bora codar! 🚀
