Cours Flutter Complet 💙

Les 12 chapitres essentiels — widgets, state, navigation, API et publication

12
Chapitres
100+
Exemples de code
Flutter 3+
Version
A1→C2
Niveaux

CHAPITRE 01

Introduction et installation

💙 Hello Flutter
// lib/main.dart
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.

⚙️ Installation
# Installer Flutter SDK
# → 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'

⚖️ Flutter vs React Native
AspectFlutterReact Native
LangageDartJavaScript / TypeScript
RenduPropre moteur (Skia/Impeller)Composants natifs via bridge
PerformanceExcellente (compilé nativement)Bonne (New Architecture)
UIPixel-perfect identique sur toutes les plateformesComposants natifs (look natif)
Hot reloadOui (sub-seconde)Oui
Web/DesktopSupporté officiellementLimité (Expo Web)
CourbeApprendre DartConnaître JS/React
🧠 Quiz
Pourquoi Flutter n'utilise pas les composants natifs ?
Flutter dessine chaque pixel avec son propre moteur de rendu (Impeller). Avantages : UI identique sur iOS et Android (pixel-perfect), performances prévisibles (pas de bridge), liberté totale de design. Inconvénient : les widgets ne sont pas les composants natifs de la plateforme (mais Material et Cupertino les imitent fidèlement).

CHAPITRE 02

Widgets de base

🧱 Tout est Widget
// Text
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.

CHAPITRE 03

Layout (mise en page)

📐 Column, Row, Stack
// Column — empiler verticalement
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: […]),
)

CHAPITRE 04

StatefulWidget et état

🔄 StatelessWidget vs StatefulWidget
// StatelessWidget — pas d'état interne, immuable
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.

CHAPITRE 05

Listes et grilles

📋 ListView
// ListView.builder — performant pour les grandes listes
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])),
)

CHAPITRE 06

Navigation et routing

🧭 GoRouter (recommandé)
// pubspec.yaml → dependencies: go_router: ^14.0.0
// 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

📱 Bottom Navigation
Scaffold(
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'),
],
),
)

CHAPITRE 07

Formulaires

📝 Form et validation
class LoginForm extends StatefulWidget

class _LoginFormState extends State<LoginForm>

CHAPITRE 08

HTTP et API

🌐 Appels réseau avec Dio
// pubspec.yaml → dependencies: dio: ^5.0.0

import 'package:dio/dio.dart';

class ApiService

// Modèle avec fromJson / toJson
class Post
// Afficher les données avec FutureBuilder
FutureBuilder<List<Post>>(
future: apiService.getPosts(),
builder: (context, snapshot) ,
)

CHAPITRE 09

State management

📊 Riverpod (recommandé)
// pubspec.yaml → dependencies: flutter_riverpod: ^2.0.0

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

SolutionComplexitéIdéal pour
setStateSimpleÉtat local d'un widget
RiverpodMoyenApps moyennes à grandes (recommandé)
Bloc/CubitComplexeArchitecture stricte, apps enterprise
ProviderSimplePetit état partagé (prédécesseur de Riverpod)

CHAPITRE 10

Stockage local

💾 SharedPreferences et Hive
// SharedPreferences — clé/valeur simple (settings, tokens)
// 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');

// SQLite — base de données relationnelle locale
// 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

CHAPITRE 11

Publication

🚀 Publier sur les stores
# Build
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

PlateformeFichierStore
Android.aab (App Bundle)Google Play Console (25$ une fois)
iOS.ipaApp Store Connect (99$/an)
Webbuild/web/Vercel, Firebase Hosting, Netlify
macOS.app / .dmgMac App Store ou distribution directe

CHAPITRE 12

Bonnes pratiques

🧩 Packages essentiels
BesoinPackage
HTTPdio
State managementflutter_riverpod
Routinggo_router
Stockage localshared_preferences, hive
Sérialisation JSONjson_serializable + freezed
Icônesflutter_launcher_icons
Imagescached_network_image
Firebasefirebase_core + plugins
Animationsflutter_animate
✅ Bonnes pratiques

✅ À 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)

🧠 Quiz
Pourquoi utiliser const partout en Flutter ?
Les widgets const sont créés une seule fois en mémoire et ne sont jamais reconstruits lors des setState. Flutter peut comparer les références et sauter le rebuild. C'est une optimisation simple mais impactante pour la performance — utilisez const dès que possible.
FutureBuilder vs Riverpod pour les données async ?
FutureBuilder relance le Future à chaque rebuild (problème de performance). Riverpod FutureProvider cache automatiquement le résultat, gère le loading/error, et ne relance que si nécessaire. Pour les appels API, préférez toujours Riverpod.

Cours Flutter Complet — Widgets, state management, API et publication

Référence : docs.flutter.dev | pub.dev | Riverpod