Cours Flutter Complet 💙
Les 12 chapitres essentiels — widgets, state, navigation, API et publication
Introduction et installation
import 'package:flutter/material.dart';
void main()
class MyApp extends StatelessWidget
Flutter est un framework UI de Google pour créer des apps natives iOS, Android, Web et Desktop à partir d'un seul codebase. Écrit en Dart, il utilise son propre moteur de rendu (Skia/Impeller) — pas de bridge vers les composants natifs. Utilisé par Google, BMW, Alibaba, eBay et Nubank.
# → https://docs.flutter.dev/get-started/install
# Vérifier l'installation
flutter doctor
# Créer un projet
flutter create mon_app
cd mon_app
# Lancer
flutter run # Détecte l'émulateur/device
flutter run -d chrome # Web
flutter run -d macos # Desktop
# Hot reload : appuyez sur 'r' dans le terminal
# Hot restart : appuyez sur 'R'
| Aspect | Flutter | React Native |
|---|---|---|
| Langage | Dart | JavaScript / TypeScript |
| Rendu | Propre moteur (Skia/Impeller) | Composants natifs via bridge |
| Performance | Excellente (compilé nativement) | Bonne (New Architecture) |
| UI | Pixel-perfect identique sur toutes les plateformes | Composants natifs (look natif) |
| Hot reload | Oui (sub-seconde) | Oui |
| Web/Desktop | Supporté officiellement | Limité (Expo Web) |
| Courbe | Apprendre Dart | Connaître JS/React |
Widgets de base
Text(
'Hello Flutter',
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold, color: Colors.blue),
)
// Image
Image.network('https://example.com/photo.jpg')
Image.asset('assets/logo.png')
// Icon
Icon(Icons.favorite, color: Colors.red, size: 30)
// Button
ElevatedButton(
onPressed: () ,
child: Text('Cliquer'),
)
TextButton(onPressed: () , child: Text('Texte'))
IconButton(onPressed: () , icon: Icon(Icons.add))
OutlinedButton(onPressed: () , child: Text('Outlined'))
// Container (équivalent div avec style)
Container(
width: 200,
height: 100,
padding: EdgeInsets.all(16),
margin: EdgeInsets.symmetric(vertical: 8),
decoration: BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.circular(12),
boxShadow: [BoxShadow(blurRadius: 10, color: Colors.black26)],
),
child: Text('Card', style: TextStyle(color: Colors.white)),
)
// Card (Material Design)
Card(
elevation: 4,
child: Padding(
padding: EdgeInsets.all(16),
child: Text('Contenu de la card'),
),
)
En Flutter, tout est un widget. Le texte, les boutons, le padding, les colonnes, même l'app elle-même. Les widgets sont imbriqués en arbre (widget tree). Un widget décrit une partie de l'interface — Flutter le dessine à l'écran.
Layout (mise en page)
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Titre', style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold)),
const SizedBox(height: 8), // Espacement
Text('Description'),
],
)
// Row — aligner horizontalement
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('Gauche'),
Text('Droite'),
],
)
// Expanded — prendre l'espace restant
Row(
children: [
Expanded(child: Text('Prend le reste')),
SizedBox(width: 100, child: Text('Fixe')),
],
)
// Stack — superposer
Stack(
children: [
Image.network('photo.jpg'),
Positioned(
bottom: 16, left: 16,
child: Text('Overlay', style: TextStyle(color: Colors.white)),
),
],
)
// Padding
Padding(
padding: EdgeInsets.all(16),
child: Text('Avec padding'),
)
// SingleChildScrollView — contenu scrollable
SingleChildScrollView(
child: Column(children: […]),
)
StatefulWidget et état
class Greeting extends StatelessWidget
// StatefulWidget — état mutable, rebuild avec setState
class Counter extends StatefulWidget
class _CounterState extends State<Counter>
setState() déclenche un rebuild. Appelez setState(() ) chaque fois que vous modifiez une variable qui affecte l'UI. Sans setState, Flutter ne sait pas qu'il doit redessiner le widget.
Listes et grilles
ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) ,
)
// GridView
GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
crossAxisSpacing: 12,
mainAxisSpacing: 12,
),
itemCount: products.length,
itemBuilder: (context, index) ,
)
// Séparateur
ListView.separated(
itemCount: items.length,
separatorBuilder: (_, __) => Divider(),
itemBuilder: (context, index) => ListTile(title: Text(items[index])),
)
Navigation et routing
// flutter pub get
import 'package:go_router/go_router.dart';
final router = GoRouter(
routes: [
GoRoute(
path: '/',
builder: (context, state) => HomeScreen(),
),
GoRoute(
path: '/post/:id',
builder: (context, state) ,
),
],
);
// Dans MaterialApp
MaterialApp.router(routerConfig: router)
// Naviguer
context.go('/'); // Remplacer
context.push('/post/42'); // Empiler
context.pop(); // Retour
body: _screens[_currentIndex],
bottomNavigationBar: NavigationBar(
selectedIndex: _currentIndex,
onDestinationSelected: (index) ,
destinations: [
NavigationDestination(icon: Icon(Icons.home), label: 'Accueil'),
NavigationDestination(icon: Icon(Icons.search), label: 'Chercher'),
NavigationDestination(icon: Icon(Icons.person), label: 'Profil'),
],
),
)
Formulaires
class _LoginFormState extends State<LoginForm>
HTTP et API
import 'package:dio/dio.dart';
class ApiService
class Post
FutureBuilder<List<Post>>(
future: apiService.getPosts(),
builder: (context, snapshot) ,
)
State management
import 'package:flutter_riverpod/flutter_riverpod.dart';
// 1. Définir un provider
final counterProvider = StateProvider<int>((ref) => 0);
// Provider pour les données async
final postsProvider = FutureProvider<List<Post>>((ref) async );
// 2. Wrapper l'app avec ProviderScope
void main()
// 3. Consommer dans un widget
class CounterScreen extends ConsumerWidget
| Solution | Complexité | Idéal pour |
|---|---|---|
| setState | Simple | État local d'un widget |
| Riverpod | Moyen | Apps moyennes à grandes (recommandé) |
| Bloc/Cubit | Complexe | Architecture stricte, apps enterprise |
| Provider | Simple | Petit état partagé (prédécesseur de Riverpod) |
Stockage local
// pubspec.yaml → shared_preferences: ^2.0.0
import 'package:shared_preferences/shared_preferences.dart';
// Sauvegarder
final prefs = await SharedPreferences.getInstance();
await prefs.setString('token', 'abc123');
await prefs.setBool('darkMode', true);
await prefs.setInt('launchCount', 5);
// Lire
final token = prefs.getString('token'); // String?
final dark = prefs.getBool('darkMode') ?? false;
// Supprimer
await prefs.remove('token');
// pubspec.yaml → sqflite: ^2.0.0, path: ^1.0.0
// Hive — NoSQL ultra-rapide (alternative recommandée)
// pubspec.yaml → hive: ^2.0.0, hive_flutter: ^1.0.0
Publication
flutter build apk # Android APK
flutter build appbundle # Android AAB (Play Store)
flutter build ios # iOS (nécessite Xcode + Mac)
flutter build web # Web → build/web/
# Icône de l'app
# pubspec.yaml → flutter_launcher_icons: ^0.14.0
flutter pub run flutter_launcher_icons
# Splash screen
# pubspec.yaml → flutter_native_splash: ^2.0.0
flutter pub run flutter_native_splash:create
| Plateforme | Fichier | Store |
|---|---|---|
| Android | .aab (App Bundle) | Google Play Console (25$ une fois) |
| iOS | .ipa | App Store Connect (99$/an) |
| Web | build/web/ | Vercel, Firebase Hosting, Netlify |
| macOS | .app / .dmg | Mac App Store ou distribution directe |
Bonnes pratiques
| Besoin | Package |
|---|---|
| HTTP | dio |
| State management | flutter_riverpod |
| Routing | go_router |
| Stockage local | shared_preferences, hive |
| Sérialisation JSON | json_serializable + freezed |
| Icônes | flutter_launcher_icons |
| Images | cached_network_image |
| Firebase | firebase_core + plugins |
| Animations | flutter_animate |
✅ À FAIRE
• const constructeurs (performance)
• Extraire les widgets en classes
• dispose() les controllers
• Riverpod pour l'état partagé
• GoRouter pour la navigation
• Dio pour les appels HTTP
• fromJson/toJson pour les modèles
• Thème centralisé (ThemeData)
• Tester sur iOS ET Android
❌ À ÉVITER
• Widget tree trop profond (un seul fichier)
• setState pour l'état global
• Oublier dispose() (fuites mémoire)
• Logique métier dans les widgets
• FutureBuilder dans build() sans cache
• Ignorer les null-safety
• print() en production (utiliser logger)
• Hardcoder les couleurs/tailles
• Ignorer les performances (DevTools)
🏠 Hub Programmation
⚛️ Cours React
📱 Cours React Native
🔷 Cours TypeScript
Cours Flutter Complet — Widgets, state management, API et publication
Référence : docs.flutter.dev | pub.dev | Riverpod

