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
-
Contador com setState: Crie um contador que começa em 0. Adicione botões para incrementar, decrementar e resetar o contador. Use
setStatepara atualizar o estado. -
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).
-
Lista dinâmica: Crie uma lista que pode ter itens adicionados e removidos. Use
setStatepara atualizar a lista quando itens forem adicionados ou removidos. -
Formulário com estado: Crie um formulário simples com um campo de texto. Use
TextEditingControllerpara gerenciar o estado do campo e exiba o valor digitado em tempo real. -
Estado condicional: Crie um widget que exiba diferentes conteúdos baseado em um estado. Por exemplo, exiba "Carregando..." quando
isLoadingfor 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()));
}