Widgets
No Flutter, o widget é uma peça da interface, um texto é um widget, um botão é um widget, uma tela é um widget, um espaçamento é um widget, uma coluna é um widget. Até a aplicação inteira começa por um widget.
Por isso é comum ouvir que no Flutter quase tudo é widget. A ideia é que a tela seja montada juntando pequenas peças. Em vez de escrever uma tela separada em XML, HTML ou usar um editor visual, o Flutter monta a interface usando código Dart.
Um exemplo simples:
Text('Servidor ativo')
Esse código cria um widget de texto.
Agora, se quisermos centralizar esse texto:
Center(
child: Text('Servidor ativo'),
)
Aqui temos dois widgets:
Center
└── Text
O Center é um widget que centraliza outro widget. O Text é o widget que mostra o texto. Essa ideia de um widget dentro de outro é a base do Flutter.
Widget como árvore
A interface no Flutter é formada como uma árvore.
MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Servidores'),
),
body: Center(
child: Text('Servidor ativo'),
),
),
)
Cada parte tem uma responsabilidade.
- O
MaterialAppconfigura a aplicação. - O
Scaffoldcria a estrutura básica da tela. - O
AppBarcria a barra superior. - O
bodydefine o conteúdo principal da tela. - O
Centercentraliza o conteúdo. - O
Textmostra o texto.
Então, quando a tela aparece, ela não surge de um único bloco. Ela é o resultado de vários widgets combinados.
Widgets de conteúdo e widgets de layout
Nem todo widget tem a mesma função, alguns widgets mostram conteúdo, como:
Text('Servidor Web')
E:
Icon(Icons.storage)
Outros widgets organizam a tela:
Column()
Row()
Center()
Padding()
SizedBox()
Container()
Por exemplo:
Padding(
padding: EdgeInsets.all(16),
child: Text('Servidor Web'),
)
O Padding adiciona espaço ao redor do Text. A estrutura fica assim:
Padding
└── Text
O Padding não mostra um texto próprio. Ele só altera o espaço ao redor do widget filho.
StatelessWidget
O StatelessWidget é um widget sem estado interno, ou seja, ele é usado para montar uma parte da interface que não precisa guardar dados que mudam durante o uso da tela.
Por exemplo, uma tela que apenas mostra informações fixas pode ser um StatelessWidget:
Text('Servidor Web')
Esse texto não muda sozinho. Ele apenas aparece na tela. Agora pensando em uma tela simples de detalhes de servidor:
Nome: Servidor Web
IP: 192.168.0.10
Status: Ativo
Se esses dados forem recebidos prontos e a tela só precisar mostrar eles, um StatelessWidget já resolve.
Quando usar StatelessWidget
Use StatelessWidget quando a tela ou parte da tela não precisa mudar por conta própria, como:
- Tela de apresentação
- Cabeçalho fixo
- Card de servidor já preenchido
- Texto de aviso
- Botão que apenas chama uma ação externa
- Layout fixo
- Tela que recebe dados prontos e só mostra
O StatelessWidget não significa que os dados nunca mudam. Um StatelessWidget não guarda estado interno, mas ele pode receber dados diferentes de fora, exemplo:
CardServidor(
nome: 'Servidor Banco',
ip: '192.168.0.20',
status: 'Inativo',
)
Aqui usamos o mesmo CardServidor, só que com outros valores. O widget continua sendo sem estado, porque ele não controla a mudança. Ele só recebe os dados e mostra. A mudança vem de fora.
StatefulWidget
O StatefulWidget é um widget com estado, ou seja, ele é usado quando a tela, ou uma parte da tela, precisa guardar algum dado que pode mudar durante o uso da aplicação.
Por exemplo:
Status: Ativo
Se esse status puder mudar para:
Status: Inativo
Então a tela precisa guardar o valor atual do status em algum lugar. Nesse caso, usamos um StatefulWidget.
O que é estado?
O estado é qualquer informação que a interface precisa lembrar enquanto a aplicação está rodando. Exemplos de estado:
- texto digitado em um campo
- item selecionado em uma lista
- status atual de um servidor
- contador de cliques
- checkbox marcado ou desmarcado
- lista de servidores carregada na tela
- mensagem de erro exibida no formulário
No caso de um app de servidores, podemos ter um estado assim:
String status = 'Ativo';
Esse valor começa como Ativo, mas pode mudar depois para Inativo.
Quando usar StatefulWidget
Use o StatefulWidget quando a tela precisa guardar alguma informação que muda durante o uso, como:
- Tela de cadastro com campos preenchidos
- Tela com botão que altera status
- Tela com contador
- Tela com checkbox
- Tela com carregamento de dados
- Tela com lista que recebe novos itens
- Tela com mensagem de erro ou sucesso
Quando não usar StatefulWidget
Não precisamos usar StatefulWidget quando a parte da tela só recebe dados e mostra. Por exemplo, este card pode continuar sendo StatelessWidget:
class CardServidor extends StatelessWidget {
final String nome;
final String ip;
final String status;
const CardServidor({
super.key,
required this.nome,
required this.ip,
required this.status,
});
@override
Widget build(BuildContext context) {
return ListTile(
title: Text(nome),
subtitle: Text('IP: $ip'),
trailing: Text(status),
);
}
}
Ele recebe os dados prontos e apenas exibe. Se a tela de fora trocar o status e criar o CardServidor com outro valor, ele mostra o novo valor. O card em si não precisa guardar nada.
setState
O setState é o método usado para avisar ao Flutter que algum estado mudou e que a tela precisa ser reconstruída. No tópico anterior, vimos que o StatefulWidget guarda dados que podem mudar, como:
String status = 'Ativo';
Mas mudar essa variável sozinho não basta. Por exemplo:
status = 'Inativo';
Isso altera o valor na memória, mas o Flutter não sabe automaticamente que precisa redesenhar a tela. Para isso, usamos setState.