Module4 Flutter
Module4 Flutter
Objectifs du Module
Comprendre les fondements du framework Flutter
Maîtriser l'installation et la configuration de l'environnement
Apprendre les concepts de base de Dart et Flutter
Développer des applications mobiles multiplateformes avec Flutter
Plan du module
1. Introduction à Flutter
2. Installation et configuration
3. Concepts de base du langage Dart
4. Création d'un premier projet Flutter
5. Les widgets et leur composition
6. Stateless vs Stateful widgets
7. Navigation entre écrans
8. Gestion des images et assets
9. Formulaires et validation
1. Introduction à Flutter
Architecture de Flutter
Couches principales
2. Installation et configuration
Prérequis
Windows, macOS ou Linux
Git pour le contrôle de version
Éditeur de code (VS Code, Android Studio, IntelliJ)
Pour le développement iOS : Mac avec Xcode
Pour le développement Android : Android Studio et SDK
# Vérifier l'installation
flutter doctor
Configuration de l'éditeur
VS Code
Flutter Doctor
Outil de diagnostic pour vérifier la configuration :
flutter doctor
Introduction à Dart
Dart est un langage de programmation développé par Google :
Variables et constantes
// Variables // Constantes
const double PI = 3.14159;
var nom = 'Flutter'; // Type inféré final String aujourd'hui = [Link]().toIso8601String();
String prenom = 'Dart'; // Type explicite
// Différence entre const et final
// const : constante à la compilation
// Variables nullables (Dart 2.12+) const List<int> constList = [1, 2, 3];
// final : constante à l'exécution
String? texteOptional; // Peut être null final List<int> finalList = [[Link]().day];
// Variables late
late String description;
Opérateurs en Dart
// Arithmétiques // Comparaison
int somme = 5 + 3; bool égal = 5 == 3; // false
int différence = 5 - 3; bool différent = 5 != 3; // true
int produit = 5 * 3; bool supérieur = 5 > 3; // true
double quotient = 5 / 3; bool inférieur = 5 < 3; // false
int modulo = 5 % 3;
// Logiques
// Incrémentation bool et = true && false; // false
int a = 5; bool ou = true || false; // true
a++; // a = 6 bool non = !true; // false
a--; // a = 5
Structures conditionnelles
// If-else // Switch-case
if (age >= 18) { switch (fruit) {
print('Majeur'); case 'pomme':
} else { print('Rouge ou verte');
break;
print('Mineur');
case 'banane':
} print('Jaune');
break;
// Opérateur ternaire default:
String statut = age >= 18 ? 'Majeur' : 'Mineur'; print('Autre fruit');
}
// Null-aware operators
String? nom;
print(nom ?? 'Inconnu'); // 'Inconnu' si nom est null
Structures itératives
// Boucle for // Boucle while
for (int i = 0; i < 5; i++) { int compteur = 0;
print('Itération $i'); while (compteur < 5) {
}
print('Compteur: $compteur');
// Boucle for-in (sur collections) compteur++;
List fruits = ['pomme', 'banane', 'orange']; }
for (String fruit in fruits) {
print(fruit); // Boucle do-while
} int nombre = 0;
do {
print('Nombre: $nombre');
nombre++;
} while (nombre < 3);
Fonctions
// Fonction basique // Paramètres optionnels positionnels
String formater(String texte, [bool majuscules = false]) {
void saluer(String nom) { return majuscules ? [Link]() : texte;
print('Bonjour $nom !'); }
} // Fonctions fléchées
int multiplier(int a, int b) => a * b;
// Fonction avec retour // Fonctions comme paramètres
int additionner(int a, int b) { void executerOperation(int a, int b, int Function(int, int) operation) {
print('Résultat: ${operation(a, b)}');
return a + b; }
}
Le fichier [Link]
import 'package:flutter/[Link]';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Ma première application',
theme: ThemeData(
primarySwatch: [Link],
),
home: MyHomePage(title: 'Page d\'accueil'),
);
}
}
2025 Master 2 Réseaux Informatiques et Multimédia 25
Cours Programmation Mobile - Module 4: Flutter
Exécuter l'application
# Dans le répertoire du projet
flutter run
Layouts en Flutter
// Row (disposition horizontale) // Stack (superposition)
Row( Stack(
mainAxisAlignment: [Link], children: [
children: [ [Link]('assets/[Link]'),
Icon([Link]), Positioned(
Icon([Link]), bottom: 16.0,
Icon([Link]), right: 16.0,
], child: ElevatedButton(
) onPressed: () {},
child: Text('Action'),
// Column (disposition verticale) ),
Column( ),
crossAxisAlignment: [Link], ],
children: [ )
Text('Titre'), // Wrap (disposition avec retour à la ligne)
Text('Sous-titre'), Wrap(
Text('Description'), spacing: 8.0,
], runSpacing: 8.0,
) children: [
Chip(label: Text('Flutter')),
Chip(label: Text('Dart')),
Chip(label: Text('Mobile')),
Chip(label: Text('App')),
],
2025 Master 2 Réseaux Informatiques et Multimédia ) 31
Cours Programmation Mobile - Module 4: Flutter
Listes et grilles
ListView : Liste défilante
[Link](
itemCount: [Link],
itemBuilder: (context, index) {
return ListTile(
title: Text(items[index].title),
subtitle: Text(items[index].description),
);
},
)
[Link](
crossAxisCount: 2,
children: [Link](6, (index) {
return Card(
child: Center(
child: Text('Item $index'),
),
);
}),
)
StatelessWidget
Immuable : propriétés ne changent pas après initialisation
Sans état interne : le widget ne se "souvient" de rien
Rebuild complet : reconstruit entièrement lors des changements
Performance : généralement plus performant car plus simple
StatelessWidget (suite)
class MonBouton extends StatelessWidget {
final String texte; // Utilisation du widget stateless
final VoidCallback onPressed;
@override
const MonBouton({Key? key, required [Link], required [Link]})
: super(key: key); Widget build(BuildContext context) {
@override return Scaffold(
Widget build(BuildContext context) {
return ElevatedButton( appBar: AppBar(
onPressed: onPressed,
child: Text(texte), title: Text('Exemple'),
}
);
),
}
body: Center(
child: MonBouton(
texte: 'Cliquez-moi',
onPressed: () {
print('Bouton cliqué');
},
),
),
);
}
2025 Master 2 Réseaux Informatiques et Multimédia 36
Cours Programmation Mobile - Module 4: Flutter
StatefulWidget
Mutable : peut changer d'état interne
Gère un état : stocke des données qui peuvent changer
Rebuild partiel : peut mettre à jour seulement les parties nécessaires
Cycle de vie : dispose de méthodes comme initState, dispose
StatefulWidget (suite)
class Compteur extends StatefulWidget { // Exemple de gestion d'état avec StatefulWidget
@override class ToggleWidget extends StatefulWidget {
@override
_CompteurState createState() => _CompteurState();
_ToggleWidgetState createState() => _ToggleWidgetState();
} }
class _CompteurState extends State { class _ToggleWidgetState extends State {
int _valeur = 0; bool _isOn = false;
@override
void _incrementer() { Widget build(BuildContext context) {
setState(() { return Column(
children: [
_valeur++; Text(_isOn ? 'ON' : 'OFF'),
}); Switch(
} value: _isOn,
@override onChanged: (newValue) {
Widget build(BuildContext context) { setState(() {
return Column( _isOn = newValue;
});
children: [
},
Text('Valeur: $_valeur'), ),
ElevatedButton( ],
onPressed: _incrementer, );
child: Text('Incrémenter'), }
), }
],
);}}
2025 Master 2 Réseaux Informatiques et Multimédia 38
Cours Programmation Mobile - Module 4: Flutter
Affichage statique
Dépend uniquement de ses propriétés
Ex: boutons, icônes, textes, cartes informatives
StatefulWidget
Interface interactive
Changement d'état interne
Ex: formulaires, animations, chargement de données
Routes nommées
Définir les routes au niveau de l'application :
return Scaffold(
appBar: AppBar(title: Text(args['title'])),
body: Center(
child: Text('ID du produit: ${args['id']}'),
),
);
}
}
// Depuis internet
[Link]('[Link]
// Avec personnalisation
[Link](
'assets/images/[Link]',
width: 200,
height: 150,
fit: [Link], // Mode d'ajustement
)
assets/
├── images/
│ ├── [Link] # 1x (baseline)
│ ├── 2.0x/
│ │ └── [Link] # 2x resolution
│ └── 3.0x/
│ └── [Link] # 3x resolution
Icônes et polices
Icônes
# Dans [Link]
flutter:
fonts:
- family: Montserrat
fonts:
- asset: fonts/[Link]
- asset: fonts/[Link]
weight: 700
Text(
'Texte stylisé',
style: TextStyle(fontFamily: 'Montserrat'),
)
9. Formulaires et validation
Créer un formulaire
// Clé pour identifier et valider le formulaire // Suite du formulaire
final _formKey = GlobalKey<FormState>(); ElevatedButton(
onPressed: () {
// Dans le widget build if (_formKey.currentState!.validate()) {
Form( // Traitement du formulaire
key: _formKey, [Link](context).showSnackBar(
child: Column( SnackBar(content: Text('Traitement en cours')),
children: <Widget>[ );
TextFormField( }
decoration: InputDecoration(labelText: 'Nom'), },
validator: (value) { child: Text('Soumettre'),
if (value == null || [Link]) { ),
return 'Veuillez entrer un nom';
} // Récupération des valeurs
return null; // Dans l'événement onSaved:
}, String _nom;
), onSaved: (value) => _nom = value,
],
), // Sauvegarde du formulaire
) _formKey.currentState!.save();
Contrôleurs de champs
class _MonFormulaireState extends State<MonFormulaire> { // Dans la méthode build
// Contrôleurs pour les champs @override
Widget build(BuildContext context) {
final _emailController = TextEditingController();
return Form(
final _passwordController = TextEditingController(); child: Column(
children: [
@override TextFormField(
void dispose() { controller: _emailController,
// Libérer les ressources decoration: InputDecoration(labelText: 'Email'),
_emailController.dispose(); ),
TextFormField(
_passwordController.dispose(); controller: _passwordController,
[Link](); decoration: InputDecoration(labelText: 'Mot de passe'),
} obscureText: true,
} ),
ElevatedButton(
onPressed: () {
print('Email: ${_emailController.text}');
},
child: Text('Connexion'),
),
],
),
);
}
Formulaires interactifs
TextFormField( // Exemple de validation de mot de passe
TextFormField(
decoration: InputDecoration( decoration: InputDecoration(
labelText: 'Email', labelText: 'Mot de passe',
hintText: 'Votre mot de passe',
hintText: 'exemple@[Link]', prefixIcon: Icon([Link]),
prefixIcon: Icon([Link]), border: OutlineInputBorder(),
),
border: OutlineInputBorder(),), obscureText: true,
keyboardType: [Link], validator: (value) {
validator: (value) { if (value == null || [Link]) {
return 'Veuillez entrer un mot de passe';
if (value == null || [Link]) { }
return 'Veuillez entrer un email'; if ([Link] < 8) {
return 'Le mot de passe doit contenir au moins 8 caractères';
} }
// Validation avec regex return null;
bool emailValide = RegExp( },
onSaved: (value) => _password = value,
r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$' )
).hasMatch(value);
if (!emailValide) {
return 'Veuillez entrer un email valide';
}
return null;
},
onSaved: (value) => _email = value,)
Conclusion
Flutter offre un framework complet pour le développement mobile
multiplateforme
Le langage Dart est moderne et adapté au développement d'interfaces
L'approche basée sur les widgets permet une grande flexibilité
La documentation est riche et la communauté active
Les performances sont excellentes comparées aux autres solutions
multiplateformes
Ressources complémentaires
Documentation officielle Flutter
Cookbook Flutter
Dart documentation
Flutter packages
Flutter Community
FlutterFire (Firebase)
Questions ?
Merci pour votre attention !
Ressources complémentaires
Documentation officielle Flutter
Cookbook Flutter
Dart documentation
Flutter packages