Esses 5 truques do Flutter transformaram o meu código confuso em magia
Eu não percebia o quão bagunçado meu código estava — até ver como é a aparência de um código limpo de verdade.” — Desenvolvedor às 2 da manhã.
No começo, tudo parecia bem. Meu app rodava. Os widgets renderizavam. Os usuários estavam felizes… na maior parte do tempo. Mas, com o passar do tempo, os bugs ficaram mais difíceis de rastrear, a performance caiu e só de olhar para o meu código eu já ficava com dor de cabeça.
Foi aí que comecei a aprender pequenos truques. Desde simplificar a árvore de widgets até escrever uma lógica mais inteligente, essas mudanças não apenas melhoraram meu código… elas mudaram a minha forma de pensar como desenvolvedor.
Seja você um iniciante ou alguém que já publicou alguns apps, aqui estão 5 truques de Flutter que instantaneamente tornaram meu código mais limpo, rápido e fácil de manter.
1. Use métodos de extension para lógicas reutilizáveis.
Em vez de poluir seus widgets com funções utilitárias ou repetir a mesma lógica, mova-as para métodos de extensão (extension methods) limpos e legíveis. Eles tornam seu código mais expressivo e reutilizável em todo o aplicativo.
import 'package:flutter/material.dart';
extension BuildContextX on BuildContext {
/// Screen Size
Size get size => MediaQuery.sizeOf(this);
double get width => size.width;
double get height => size.height;
/// Responsive Units
double get shortestSide => size.shortestSide;
bool get isMobile => shortestSide < 600;
bool get isTablet => shortestSide >= 600 && shortestSide < 1024;
bool get isDesktop => shortestSide >= 1024;
void hideKeyboard() => FocusScope.of(this).unfocus();
}
2. Substitua condições if repetitivas por um Map.
Quando a condição depende de uma constante ou de um enum, substitua-a por uma busca em um mapa. É mais rápido e muito mais limpo.
Antes:
Icon getStatusIcon(String status) {
if (status == 'success') {
return const Icon(Icons.check_circle, color: Colors.green);
} else if (status == 'error') {
return const Icon(Icons.error, color: Colors.red);
} else if (status == 'pending') {
return const Icon(Icons.hourglass_empty, color: Colors.orange);
} else {
return const Icon(Icons.help_outline);
}
}
Depois:
final Map<String, Icon> _statusIcons = {
'success': const Icon(Icons.check_circle, color: Colors.green),
'error': const Icon(Icons.error, color: Colors.red),
'pending': const Icon(Icons.hourglass_empty, color: Colors.orange),
};
Icon getStatusIcon(String status) => _statusIcons[status] ??
const Icon(Icons.help_outline, color: Colors.grey);
3. Use late final em vez de initState sempre que possível.
Para configurações simples de estado, você geralmente pode pular completamente o initState() usando variáveis late final. Isso funciona muito bem para controllers, animações ou qualquer coisa inicializada apenas uma vez e que nunca será reatribuída.
late final TextEditingController _controller = TextEditingController();
4. Use ValueNotifier para uma UI Reativa Simples sem Gerenciamento de Estado Completo.
Quando você precisa de uma reatividade leve — como alternar um tema, um contador ou uma validação de formulário — o ValueNotifier é uma alternativa limpa aos gerenciamentos de estado mais pesados. Ele é ideal para estados locais que não precisam sobreviver entre diferentes telas.
final ValueNotifier<int> counter = ValueNotifier(0);
ValueListenableBuilder(
valueListenable: counter,
builder: (_, value, __) => Text('Count: $value'),
)
5. Extraia Widgets, mesmo os pequenos.
Não hesite em extrair até mesmo pequenos pedaços da interface (UI) para seus próprios widgets. Isso mantém o seu método build() limpo, melhora a legibilidade e torna seu código mais fácil de manter e reutilizar.
@override
Widget build(BuildContext context) {
return Row(
children: const [
ProfilePicture(url: 'https://example.com/avatar.png'),
SizedBox(width: 12),
UserName(name: 'John Doe'),
],
);
}
class ProfilePicture extends StatelessWidget {
final String url;
const ProfilePicture({required this.url, super.key});
@override
Widget build(BuildContext context) {
return CircleAvatar(
radius: 24,
backgroundImage: NetworkImage(url),
);
}
}
class UserName extends StatelessWidget {
final String name;
const UserName({required this.name, super.key});
@override
Widget build(BuildContext context) {
return Text(
name,
style: Theme.of(context).textTheme.titleMedium,
);
}
}
Quer esteja a trabalhar sozinho ou em equipa, um código limpo é a base que mantém o seu projeto saudável à medida que cresce.
Experimente algumas destas dicas na sua próxima funcionalidade.