Pular para o conteúdo principal

Estados com StatefulWidget

setState

setState é usado em StatefulWidget para notificar o Flutter que o estado mudou e o widget precisa ser reconstruído:

class Contador extends StatefulWidget {

State<Contador> createState() => _ContadorState();
}

class _ContadorState extends State<Contador> {
int _contador = 0;

void _incrementar() {
setState(() {
_contador++;
});
}


Widget build(BuildContext context) {
return Column(
children: [
Text('Contador: $_contador'),
ElevatedButton(
onPressed: _incrementar,
child: Text('Incrementar'),
),
],
);
}
}

Conceitos básicos de estado

O estado é qualquer dado que pode mudar durante o ciclo de vida do widget:

  • Dados de formulários
  • Contadores
  • Listas dinâmicas
  • Flags de UI (loading, error, etc.)

Quando usar StatefulWidget

Use StatefulWidget quando:

  • O widget precisa mudar dinamicamente
  • Você precisa gerenciar estado local
  • O widget responde a interações do usuário
  • Você precisa fazer animações

Use StatelessWidget quando:

  • O widget é estático
  • Todos os dados vêm de parâmetros
  • Não há necessidade de mudanças após a criação

Exercícios

  1. Contador com setState: Crie um contador que começa em 0. Adicione botões para incrementar, decrementar e resetar o contador. Use setState para atualizar o estado.

  2. Toggle de estado: Crie um widget que tenha um botão que alterna entre dois estados (ligado/desligado). Exiba visualmente o estado atual (por exemplo, mudando a cor ou o texto).

  3. Lista dinâmica: Crie uma lista que pode ter itens adicionados e removidos. Use setState para atualizar a lista quando itens forem adicionados ou removidos.

  4. Formulário com estado: Crie um formulário simples com um campo de texto. Use TextEditingController para gerenciar o estado do campo e exiba o valor digitado em tempo real.

  5. Estado condicional: Crie um widget que exiba diferentes conteúdos baseado em um estado. Por exemplo, exiba "Carregando..." quando isLoading for true, e o conteúdo quando for false.

Soluções

Ver solução do exercício 1
import 'package:flutter/material.dart';

class Contador extends StatefulWidget {

State<Contador> createState() => _ContadorState();
}

class _ContadorState extends State<Contador> {
int _contador = 0;

void _incrementar() {
setState(() {
_contador++;
});
}

void _decrementar() {
setState(() {
_contador--;
});
}

void _resetar() {
setState(() {
_contador = 0;
});
}


Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Contador')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Contador: $_contador', style: TextStyle(fontSize: 32)),
SizedBox(height: 20),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: _decrementar,
child: Text('-'),
),
SizedBox(width: 20),
ElevatedButton(
onPressed: _incrementar,
child: Text('+'),
),
],
),
SizedBox(height: 10),
ElevatedButton(
onPressed: _resetar,
child: Text('Resetar'),
),
],
),
),
);
}
}

void main() {
runApp(MaterialApp(home: Contador()));
}
Ver solução do exercício 2
import 'package:flutter/material.dart';

class Toggle extends StatefulWidget {

State<Toggle> createState() => _ToggleState();
}

class _ToggleState extends State<Toggle> {
bool _ligado = false;

void _alternar() {
setState(() {
_ligado = !_ligado;
});
}


Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Toggle')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
width: 100,
height: 100,
color: _ligado ? Colors.green : Colors.red,
child: Center(
child: Text(
_ligado ? 'LIGADO' : 'DESLIGADO',
style: TextStyle(color: Colors.white),
),
),
),
SizedBox(height: 20),
ElevatedButton(
onPressed: _alternar,
child: Text('Alternar'),
),
],
),
),
);
}
}

void main() {
runApp(MaterialApp(home: Toggle()));
}
Ver solução do exercício 3
import 'package:flutter/material.dart';

class ListaDinamica extends StatefulWidget {

State<ListaDinamica> createState() => _ListaDinamicaState();
}

class _ListaDinamicaState extends State<ListaDinamica> {
List<String> _itens = [];

void _adicionarItem() {
setState(() {
_itens.add('Item ${_itens.length + 1}');
});
}

void _removerItem(int index) {
setState(() {
_itens.removeAt(index);
});
}


Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Lista Dinâmica')),
body: ListView.builder(
itemCount: _itens.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(_itens[index]),
trailing: IconButton(
icon: Icon(Icons.delete),
onPressed: () => _removerItem(index),
),
);
},
),
floatingActionButton: FloatingActionButton(
onPressed: _adicionarItem,
child: Icon(Icons.add),
),
);
}
}

void main() {
runApp(MaterialApp(home: ListaDinamica()));
}
Ver solução do exercício 4
import 'package:flutter/material.dart';

class FormularioEstado extends StatefulWidget {

State<FormularioEstado> createState() => _FormularioEstadoState();
}

class _FormularioEstadoState extends State<FormularioEstado> {
final _controller = TextEditingController();


void dispose() {
_controller.dispose();
super.dispose();
}


Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Formulário')),
body: Padding(
padding: EdgeInsets.all(16),
child: Column(
children: [
TextField(
controller: _controller,
decoration: InputDecoration(labelText: 'Digite algo'),
onChanged: (value) {
setState(() {});
},
),
SizedBox(height: 20),
Text(
'Valor digitado: ${_controller.text}',
style: TextStyle(fontSize: 18),
),
],
),
),
);
}
}

void main() {
runApp(MaterialApp(home: FormularioEstado()));
}
Ver solução do exercício 5
import 'package:flutter/material.dart';

class EstadoCondicional extends StatefulWidget {

State<EstadoCondicional> createState() => _EstadoCondicionalState();
}

class _EstadoCondicionalState extends State<EstadoCondicional> {
bool _isLoading = false;

void _simularCarregamento() {
setState(() {
_isLoading = true;
});

Future.delayed(Duration(seconds: 2), () {
setState(() {
_isLoading = false;
});
});
}


Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Estado Condicional')),
body: Center(
child: _isLoading
? CircularProgressIndicator()
: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Conteúdo carregado!', style: TextStyle(fontSize: 20)),
SizedBox(height: 20),
ElevatedButton(
onPressed: _simularCarregamento,
child: Text('Recarregar'),
),
],
),
),
);
}
}

void main() {
runApp(MaterialApp(home: EstadoCondicional()));
}