Flutter Widgets — les blocs de construction fondamentaux de l'interface utilisateur dans le framework Google Flutter, publié en version stable 1.0 en décembre 2018. Dans Flutter, tout est un widget : des écrans et boutons aux espacements et alignements. Les widgets forment un arbre (widget tree) que Flutter rend sur son propre moteur Skia/Impeller, en contournant les composants natifs de la plateforme. Selon Google I/O (2025), Flutter est utilisé dans plus de 500 000 applications sur Google Play et l'App Store. L'architecture Flutter divise les widgets en StatelessWidget (immuables) et StatefulWidget (avec état mutable via un objet State).
Points Clés
Flutter Widgets — tous les éléments d'UI dans le framework Flutter, implémentés en tant que classes Dart immuables. Un widget est la configuration d'un élément d'UI : sa taille, sa couleur, sa position et ses gestionnaires d'événements. Contrairement à Android (XML + View) ou iOS (Storyboard + UIView), Flutter n'utilise pas de composants natifs — tout est dessiné par le moteur Skia (Android/iOS/Linux) ou Impeller (iOS/macOS) sur un Canvas. Cela garantit une apparence cohérente sur toutes les plateformes sans divergence de plateforme. Flutter est livré avec deux ensembles de widgets : Material Widgets (Google Material Design 3 pour Android/web) et Cupertino Widgets (Apple HIG pour iOS/macOS). Le développeur peut combiner les deux ensembles dans une seule application. Chaque widget a une méthode build() qui retourne un widget enfant ou une composition de ceux-ci — c'est ainsi que l'arbre de widgets est construit.
Flutter fonctionne avec trois arbres : Widget Tree (configuration, créée par le développeur), Element Tree (mapping du widget à sa position dans l'arbre, géré par le framework) et Render Tree (objets qui calculent la disposition et effectuent le peinture). Un Widget crée un Element, qui crée un RenderObject. L'Element est réutilisé lors d'un changement de configuration (rebuild) — c'est le mécanisme d'optimisation de Flutter : si le type de widget et la key correspondent, l'Element n'est pas recréé mais mis à jour avec la nouvelle configuration. Comprendre les trois arbres est la clé pour optimiser les performances des applications Flutter.
StatelessWidget — un widget qui ne stocke pas d'état interne. Il reçoit des paramètres via le constructeur et les affiche sans possibilité de modification après le build. StatelessWidget est idéal pour les éléments statiques : en-têtes, icônes, avatars, listes avec données fixes. La méthode build() est appelée une fois à la création et lorsque le widget parent change. Comme StatelessWidget n'a pas d'état, il ne nécessite pas d'objet State séparé — build() est défini directement dans la classe du widget.
import 'package:flutter/material.dart';
class ProfileHeader extends StatelessWidget {
final String name;
final String avatarUrl;
const ProfileHeader({super.key, required this.name, required this.avatarUrl});
@override
Widget build(BuildContext context) {
return Row(
children: [
CircleAvatar(
radius: 24,
backgroundImage: NetworkImage(avatarUrl),
),
const SizedBox(width: 12),
Text(
name,
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
],
);
}
}ProfileHeader — un StatelessWidget qui reçoit name et avatarUrl via le constructeur. CircleAvatar affiche l'avatar, Text affiche le nom. Le widget ne peut pas modifier ces valeurs après la création. Utiliser un constructeur const (const ProfileHeader) permet à Flutter de réutiliser l'instance du widget lors du rebuild du parent — une micro-optimisation recommandée pour tous les StatelessWidget.
StatefulWidget — un widget avec état mutable stocké dans un objet State séparé. Le StatefulWidget lui-même est immuable, comme StatelessWidget. La partie mutable est déléguée à State : State est un objet créé une fois qui survit à de multiples rebuilds du widget. Lorsque l'état change (setState()), Flutter appelle build() sur State, mettant à jour l'UI. StatefulWidget est utilisé pour les éléments interactifs : compteurs, champs de texte, cases à cocher, animations, minuteries.
import 'package:flutter/material.dart';
class LikeButton extends StatefulWidget {
const LikeButton({super.key});
@override
State<LikeButton> createState() => _LikeButtonState();
}
class _LikeButtonState extends State<LikeButton> {
bool liked = false;
int count = 42;
void _toggleLike() {
setState(() {
liked = !liked;
count += liked ? 1 : -1;
});
}
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: _toggleLike,
child: Text(liked ? '♥ $count' : '♡ $count'),
);
}
}LikeButton — un StatefulWidget avec la classe State _LikeButtonState. Les champs liked et count sont l'état stocké dans State et ne sont pas réinitialisés lors du rebuild. setState() notifie Flutter que l'UI doit être reconstruite. Flutter ne recrée pas State à chaque rebuild du parent — seulement lorsque la configuration change (key ou type de widget). Chez IT Sectr, nous utilisons StatelessWidget pour l'affichage et StatefulWidget pour les composants interactifs, suivant le principe de minimiser StatefulWidget jusqu'aux limites de la mutation.
Widget Tree — une structure hiérarchique de widgets décrivant l'UI de l'application. Flutter convertit le Widget Tree en Element Tree : chaque Widget crée un Element, qui suit sa position dans l'arbre et sa connexion à un RenderObject. Le Render Tree effectue la disposition (détermination des tailles et positions) et le peinture (rendu). L'Element est une couche d'optimisation clé : si le type de widget et la key n'ont pas changé lors d'un rebuild, l'Element est réutilisé, mettant à jour la configuration sans recréer le RenderObject. Cela garantit les performances de Flutter à des taux d'images élevés (60/120 FPS).
import 'package:flutter/material.dart';
class HomeScreen extends StatelessWidget {
const HomeScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Widgets Flutter')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(Icons.flutter_dash, size: 80),
const SizedBox(height: 16),
const Text(
'Bonjour, Flutter !',
style: TextStyle(fontSize: 24),
),
],
),
),
);
}
}Arbre de widgets HomeScreen : Scaffold → AppBar + Center → Column → [Icon, SizedBox, Text]. Scaffold est le widget racine de disposition Material Design. Center centre sa Column fille. Column dispose les enfants verticalement avec un alignement centré (mainAxisAlignment.center). Flutter calcule la disposition de haut en bas (les contraintes sont passées du parent) et les tailles de bas en haut (sizedByParent ou dimensionnement à partir des enfants).
BuildContext — un descripteur de la position du widget dans l'Element Tree. Chaque méthode build() reçoit un BuildContext, à travers lequel le widget peut accéder à : MediaQuery (taille de l'écran, orientation, densité de pixels, zone de sécurité), Theme (MaterialThemeData ou CupertinoThemeData), Navigator (pile de navigation), ScaffoldMessenger (SnackBar), InheritedWidget (passage de données vers le bas dans l'arbre). BuildContext ne doit pas être sauvegardé après la fin de build() ou utilisé en dehors d'un contexte synchrone — cela provoque des erreurs comme « Scaffold.of() called with a context that does not contain a Scaffold ». Au lieu de sauvegarder le context, utilisez le widget Builder ou le modèle InheritedWidget pour accéder aux données.
Key — un paramètre optionnel du constructeur de chaque widget (super.key). Key aide Flutter à identifier un widget lorsque l'ordre ou le nombre d'éléments dans une liste change. Sans key, Flutter compare les widgets par type et position ; lors de l'ajout d'un élément au milieu d'une liste sans key, Flutter réutilise l'Element pour le mauvais widget, provoquant des bogues d'état (StatefulWidget) et des problèmes d'animation. Utilisez ValueKey (identifiant unique) pour les listes, ObjectKey (basé sur l'objet de données), UniqueKey (garanti unique à chaque rebuild — pour une recréation forcée).
Flutter SDK (version stable 3.3+, Dart 3+) inclut plus de 200 widgets intégrés divisés en catégories : Layout (Row, Column, Stack, Container, Expanded, Flexible, Wrap, GridView, ListView, CustomScrollView), Material Design (Scaffold, AppBar, Card, Drawer, BottomNavigationBar, FloatingActionButton, TabBar, Chip, DataTable), Cupertino (CupertinoPageScaffold, CupertinoNavigationBar, CupertinoButton, CupertinoTabBar), Painting & Effects (Opacity, DecoratedBox, ClipRect, Transform, BackdropFilter, ShaderMask), Async (FutureBuilder, StreamBuilder) et Accessibility (Semantics, MergeSemantics, ExcludeSemantics). Les widgets de disposition sont la base de toute UI Flutter : Row pour les séquences horizontales, Column pour les verticales, Stack pour les éléments superposés, Container avec BoxDecoration pour la décoration.
| Catégorie | Widgets clés | Objectif |
|---|---|---|
| Layout | Row, Column, Stack, Container, Expanded, Flexible | Positionnement et dimensionnement des enfants |
| Material | Scaffold, AppBar, Card, Drawer, FAB, TabBar | Composants UI Material Design 3 |
| Cupertino | CupertinoPageScaffold, CupertinoNavigationBar, CupertinoButton | Composants stylisés iOS |
| Painting | Opacity, ClipRect, Transform, DecoratedBox, BackdropFilter | Effets visuels et clipping |
| Async | FutureBuilder, StreamBuilder | Chargement de données asynchrone avec états d'UI |
| Accessibility | Semantics, MergeSemantics | Balisage sémantique pour lecteurs d'écran |
Questions Fréquentes
StatelessWidget n'a pas d'état interne — toutes les données sont passées via le constructeur et ne changent pas. StatefulWidget stocke l'état mutable dans un objet State séparé qui survit aux rebuilds. Le changement d'état appelle setState(), et Flutter reconstruit l'UI. Utilisez StatelessWidget pour les éléments immuables ; utilisez StatefulWidget pour les éléments interactifs.
BuildContext est un descripteur de la position du widget dans l'Element Tree, passé à la méthode build(). Via le context, un widget accède à MediaQuery, Theme, Navigator, ScaffoldMessenger et InheritedWidget. BuildContext ne doit pas être sauvegardé après la fin de build(). Pour accéder aux données, utilisez le widget Builder ou InheritedWidget.
Oui, Flutter utilise Dart comme son unique langage de programmation. Dart est un langage typé statiquement avec null safety, sound null safety, extension methods et pattern matching. Pour commencer, les bases de Dart suffisent : classes, fonctions, async/await, collections. Dart se compile en code natif (AOT) via Dart Native et en JavaScript (pour le web) via Dart2JS.
Non, Flutter prend en charge six plateformes : iOS, Android, Web, macOS, Windows, Linux. Plus de 90 % du code est partagé entre toutes les plateformes. Les adaptations de plateforme (appareil photo, système de fichiers) sont implémentées via des plugins ou des platform channels. Pour le bureau, Flutter utilise le shell de fenêtrage Flutter Desktop ; pour le web, il utilise le moteur CanvasKit (WebGL) ou le moteur de rendu HTML.
Flutter atteint 60/120 FPS grâce à : son propre moteur 2D (Skia/Impeller), l'absence de pont natif (contrairement à React Native), trois arbres (Widget → Element → Render) avec réutilisation d'Element lorsque le type/la key reste inchangé, un algorithme de disposition à passage unidirectionnel (contraintes vers le bas, tailles vers le haut) et RepaintBoundary pour isoler le repeint de zones individuelles de l'écran.
Résumé
Nous développerons une application mobile clé en main
IT Sectr crée des applications iOS et Android pour les startups et les entreprises depuis 2017. Nous vous conseillerons et vous proposerons la meilleure solution.
Lisez aussi