0% ont trouvé ce document utile (0 vote)
5 vues31 pages

Flutter Summary Chapter-3

Le chapitre 3 traite de la construction et de la structuration des interfaces dans Flutter, en abordant les widgets pour afficher du contenu visuel comme le texte, les icônes et les images. Il explique également comment interagir avec l'interface via différents types de boutons et l'utilisation de StatefulWidget pour gérer l'état. Enfin, il présente des techniques de positionnement avancé avec des widgets comme Stack, Positioned, et Wrap pour une mise en page flexible et dynamique.

Transféré par

Moha Med
Copyright
© All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd
0% ont trouvé ce document utile (0 vote)
5 vues31 pages

Flutter Summary Chapter-3

Le chapitre 3 traite de la construction et de la structuration des interfaces dans Flutter, en abordant les widgets pour afficher du contenu visuel comme le texte, les icônes et les images. Il explique également comment interagir avec l'interface via différents types de boutons et l'utilisation de StatefulWidget pour gérer l'état. Enfin, il présente des techniques de positionnement avancé avec des widgets comme Stack, Positioned, et Wrap pour une mise en page flexible et dynamique.

Transféré par

Moha Med
Copyright
© All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd

Chapitre 3 : Construction et structuration des

interfaces

Explication

Sous-partie 1 : Afficher du contenu visuel (texte, icônes, images)

Widget Text - Affichage de texte

Le widget Text est fondamental pour afficher du texte dans Flutter :

// Text simple
Text('Bonjour Flutter')

// Text avec style


Text(
'Texte stylisé',
style: TextStyle(
fontSize: 24,
fontWeight: [Link],
fontStyle: [Link],
color: [Link],
letterSpacing: 2.0,
wordSpacing: 5.0,
decoration: [Link],
decorationColor: [Link],
decorationStyle: [Link],
),
)

// Text avec alignement


Text(
'Texte aligné',
textAlign: [Link], // left, right, justify, center
)

// Text multiligne avec overflow


Text(
'Texte très long qui pourrait dépasser...',
maxLines: 2,
overflow: [Link], // clip, fade, ellipsis, visible
)

RichText - Texte enrichi

Permet de combiner plusieurs styles dans un même texte :

1/31
RichText(
text: TextSpan(
text: 'Texte normal ',
style: TextStyle(color: [Link]),
children: [
TextSpan(
text: 'en gras ',
style: TextStyle(fontWeight: [Link]),
),
TextSpan(
text: 'et en couleur',
style: TextStyle(color: [Link]),
),
],
),
)

Widget Icon - Icônes Material

Flutter fournit une vaste bibliothèque d'icônes Material Design :

// Icône simple
Icon([Link])

// Icône personnalisée
Icon(
[Link],
size: 50,
color: [Link],
)

// Icônes couramment utilisées


Icon([Link])
Icon([Link])
Icon([Link])
Icon([Link])
Icon([Link])
Icon([Link])
Icon([Link])
Icon([Link])
Icon(Icons.arrow_back)
Icon(Icons.check_circle)

IconButton - Bouton avec icône

2/31
IconButton(
icon: Icon(Icons.volume_up),
iconSize: 30,
color: [Link],
tooltip: 'Augmenter le volume',
onPressed: () {
print('Icône cliquée');
},
)

Widget Image - Affichage d'images

Flutter supporte plusieurs sources d'images :

Images depuis les assets :

// Image simple
[Link]('assets/images/[Link]')

// Image avec dimensions


[Link](
'assets/images/[Link]',
width: 200,
height: 150,
fit: [Link], // cover, contain, fill, fitWidth, fitHeight
)

Images depuis le réseau :

[Link](
'[Link]
loadingBuilder: (context, child, loadingProgress) {
if (loadingProgress == null) return child;
return CircularProgressIndicator(
value: [Link] != null
? [Link] /
[Link]!
: null,
);
},
errorBuilder: (context, error, stackTrace) {
return Icon([Link]);
},
)

Images depuis la mémoire ou fichiers :

3/31
// Depuis la mémoire
[Link](uint8List)

// Depuis un fichier
[Link](File('path/to/[Link]'))

BoxFit - Modes d'ajustement d'image

[Link] : Étire l'image pour remplir la boîte (peut déformer) [Link] : Contient
l'image entière dans la boîte (peut laisser des espaces) [Link] : Remplit la boîte en
coupant l'image si nécessaire [Link] : Ajuste à la largeur [Link] : Ajuste à la
hauteur
[Link] : Taille originale
[Link] : Réduit si trop grande, sinon taille originale

CircleAvatar - Image circulaire

Parfait pour les photos de profil :

CircleAvatar(
radius: 50,
backgroundImage: NetworkImage('[Link]
backgroundColor: [Link],
)

// Avec initiales
CircleAvatar(
radius: 50,
backgroundColor: [Link],
child: Text(
'AB',
style: TextStyle(fontSize: 24, color: [Link]),
),
)

AssetImage vs NetworkImage

// Utilisation dans decoration


Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/[Link]'),
fit: [Link],
),
),
)

Widget Card - Carte Material

4/31
Conteneur avec élévation et coins arrondis :

Card(
elevation: 5,
shape: RoundedRectangleBorder(
borderRadius: [Link](15),
),
child: Padding(
padding: [Link](16),
child: Column(
children: [
[Link]('assets/[Link]'),
SizedBox(height: 10),
Text('Produit'),
Text('Prix: 29.99€'),
],
),
),
)

Sous-partie 2 : Interagir avec l'interface (boutons, StatefulWidget)

Types de boutons Material

ElevatedButton - Bouton élevé

ElevatedButton(
onPressed: () {
print('Bouton cliqué');
},
child: Text('Valider'),
style: [Link](
backgroundColor: [Link],
foregroundColor: [Link],
padding: [Link](horizontal: 30, vertical: 15),
shape: RoundedRectangleBorder(
borderRadius: [Link](10),
),
elevation: 5,
),
)

// Bouton désactivé
ElevatedButton(
onPressed: null, // null désactive le bouton
child: Text('Désactivé'),
)

TextButton - Bouton texte plat

5/31
TextButton(
onPressed: () {},
child: Text('Annuler'),
style: [Link](
foregroundColor: [Link],
),
)

OutlinedButton - Bouton avec bordure

OutlinedButton(
onPressed: () {},
child: Text('Plus d\'infos'),
style: [Link](
side: BorderSide(color: [Link], width: 2),
),
)

IconButton - Bouton icône

IconButton(
icon: Icon(Icons.favorite_border),
onPressed: () {},
iconSize: 30,
color: [Link],
)

FloatingActionButton - Bouton d'action flottant

FloatingActionButton(
onPressed: () {},
child: Icon([Link]),
backgroundColor: [Link],
tooltip: 'Ajouter',
)

// Version étendue
[Link](
onPressed: () {},
icon: Icon([Link]),
label: Text('Nouveau'),
)

GestureDetector - Détection de gestes

Widget puissant pour détecter divers gestes :

6/31
GestureDetector(
onTap: () => print('Tap simple'),
onDoubleTap: () => print('Double tap'),
onLongPress: () => print('Appui long'),
onPanUpdate: (details) => print('Glissement'),
onScaleUpdate: (details) => print('Pincement'),
child: Container(
width: 200,
height: 200,
color: [Link],
child: Center(child: Text('Touchez-moi')),
),
)

InkWell - Zone cliquable avec effet d'encre

InkWell(
onTap: () {},
onLongPress: () {},
splashColor: [Link](0.3),
highlightColor: [Link](0.1),
borderRadius: [Link](10),
child: Container(
padding: [Link](16),
child: Text('Cliquez pour effet d\'encre'),
),
)

StatefulWidget en détail

Un StatefulWidget se compose de deux classes :

7/31
// Classe du Widget (immuable)
class Compteur extends StatefulWidget {
const Compteur({Key? key}) : super(key: key);

@override
State<Compteur> createState() => _CompteurState();
}

// Classe de l'État (mutable)


class _CompteurState extends State<Compteur> {
// Variables d'état
int _compteur = 0;
bool _isVisible = true;

// Méthodes pour modifier l'état


void _incrementer() {
setState(() {
_compteur++;
});
}

void _toggleVisibility() {
setState(() {
_isVisible = !_isVisible;
});
}

@override
Widget build(BuildContext context) {
return Column(
children: [
Text('Compteur : $_compteur'),
ElevatedButton(
onPressed: _incrementer,
child: Text('Incrémenter'),
),
if (_isVisible)
Text('Visible'),
IconButton(
icon: Icon(_isVisible ? [Link] : Icons.visibility_off),
onPressed: _toggleVisibility,
),
],
);
}
}

Cycle de vie d'un StatefulWidget

8/31
class MonWidget extends StatefulWidget {
@override
_MonWidgetState createState() => _MonWidgetState();
}

class _MonWidgetState extends State<MonWidget> {


@override
void initState() {
[Link]();
// Appelé une seule fois à la création
print('initState');
}

@override
void didChangeDependencies() {
[Link]();
// Appelé après initState et quand les dépendances changent
print('didChangeDependencies');
}

@override
Widget build(BuildContext context) {
// Appelé à chaque rebuild
print('build');
return Container();
}

@override
void didUpdateWidget(MonWidget oldWidget) {
[Link](oldWidget);
// Appelé quand le widget parent se reconstruit
print('didUpdateWidget');
}

@override
void dispose() {
// Nettoyage avant destruction
print('dispose');
[Link]();
}
}

TextField - Champ de saisie

9/31
class FormExample extends StatefulWidget {
@override
_FormExampleState createState() => _FormExampleState();
}

class _FormExampleState extends State<FormExample> {


final TextEditingController _controller = TextEditingController();
String _texte = '';

@override
void dispose() {
_controller.dispose(); // Important : libérer le contrôleur
[Link]();
}

@override
Widget build(BuildContext context) {
return Column(
children: [
TextField(
controller: _controller,
decoration: InputDecoration(
labelText: 'Nom',
hintText: 'Entrez votre nom',
prefixIcon: Icon([Link]),
suffixIcon: IconButton(
icon: Icon([Link]),
onPressed: () => _controller.clear(),
),
border: OutlineInputBorder(),
),
onChanged: (value) {
setState(() {
_texte = value;
});
},
),
Text('Vous avez saisi : $_texte'),
],
);
}
}

Checkbox, Radio, Switch

class InputWidgets extends StatefulWidget {


@override
_InputWidgetsState createState() => _InputWidgetsState();
}

class _InputWidgetsState extends State<InputWidgets> {


bool _checked = false;
int selectedRadio = 1;

10/31
int _selectedRadio 1;
bool _switched = false;

@override
Widget build(BuildContext context) {
return Column(
children: [
// Checkbox
Checkbox(
value: _checked,
onChanged: (value) {
setState(() {
_checked = value!;
});
},
),

// CheckboxListTile (avec label)


CheckboxListTile(
title: Text('Accepter les conditions'),
value: _checked,
onChanged: (value) {
setState(() {
_checked = value!;
});
},
),

// Radio buttons
RadioListTile(
title: Text('Option 1'),
value: 1,
groupValue: _selectedRadio,
onChanged: (value) {
setState(() {
_selectedRadio = value as int;
});
},
),

// Switch
Switch(
value: _switched,
onChanged: (value) {
setState(() {
_switched = value;
});
},
),
],
);
}
}

11/31
Sous-partie 3 : Positionnement avancé (Stack, Positioned, Wrap,
LayoutBuilder)

Stack - Empilement de widgets

Stack permet de superposer des widgets les uns sur les autres :

Stack(
alignment: [Link], // Alignement par défaut
children: [
// Widget du fond
Container(
width: 300,
height: 300,
color: [Link],
),
// Widget au-dessus
Container(
width: 200,
height: 200,
color: [Link],
),
// Widget au premier plan
Text(
'Texte au premier plan',
style: TextStyle(color: [Link], fontSize: 20),
),
],
)

Positioned - Positionnement absolu dans Stack

12/31
Stack(
children: [
Container(
width: 300,
height: 300,
color: [Link][300],
),
// Position en haut à gauche
Positioned(
top: 10,
left: 10,
child: Icon([Link], color: [Link], size: 40),
),
// Position en bas à droite
Positioned(
bottom: 10,
right: 10,
child: ElevatedButton(
onPressed: () {},
child: Text('Bouton'),
),
),
// Centré horizontalement en haut
Positioned(
top: 10,
left: 0,
right: 0,
child: Center(child: Text('Titre')),
),
// Étire sur toute la largeur
Positioned(
bottom: 0,
left: 0,
right: 0,
height: 50,
child: Container(color: [Link](0.5)),
),
],
)

[Link] - Remplir tout l'espace

Stack(
children: [
[Link](
child: [Link]('assets/[Link]', fit: [Link]),
),
[Link](
child: Container(color: [Link](0.3)),
),
],
)

13/31
Align - Alignement dans un conteneur

Container(
width: 200,
height: 200,
color: [Link],
child: Align(
alignment: [Link],
// [Link], topCenter, topRight
// [Link], center, centerRight
// [Link], bottomCenter, bottomRight
// Alignment(x, y) où x et y sont entre -1 et 1
child: Icon([Link]),
),
)

Wrap - Disposition avec retour à la ligne

Contrairement à Row qui déborde, Wrap passe à la ligne suivante :

Wrap(
spacing: 8, // Espacement horizontal
runSpacing: 10, // Espacement vertical entre lignes
alignment: [Link],
children: [
Chip(label: Text('Flutter')),
Chip(label: Text('Dart')),
Chip(label: Text('Mobile')),
Chip(label: Text('Development')),
Chip(label: Text('UI/UX')),
Chip(label: Text('Material')),
],
)

Expanded et Flexible - Distribution d'espace

14/31
Row(
children: [
// Prend 2 parts de l'espace disponible
Expanded(
flex: 2,
child: Container(color: [Link], height: 100),
),
// Prend 1 part de l'espace disponible
Expanded(
flex: 1,
child: Container(color: [Link], height: 100),
),
],
)

// Flexible vs Expanded
Column(
children: [
// Flexible : peut être plus petit que l'espace alloué
Flexible(
child: Container(color: [Link]),
),
// Expanded : doit remplir l'espace alloué
Expanded(
child: Container(color: [Link]),
),
],
)

LayoutBuilder - Responsive design

Permet d'obtenir les contraintes du parent et adapter le layout :

15/31
LayoutBuilder(
builder: (context, constraints) {
// [Link] et [Link] disponibles

if ([Link] > 600) {


// Layout pour grand écran
return Row(
children: [
Expanded(child: Menu()),
Expanded(flex: 3, child: Content()),
],
);
} else {
// Layout pour petit écran
return Column(
children: [
Menu(),
Expanded(child: Content()),
],
);
}
},
)

AspectRatio - Maintenir un ratio

AspectRatio(
aspectRatio: 16 / 9, // Ratio largeur/hauteur
child: Container(
color: [Link],
child: Center(child: Text('16:9')),
),
)

FractionallySizedBox - Taille fractionnelle

FractionallySizedBox(
widthFactor: 0.5, // 50% de la largeur du parent
heightFactor: 0.3, // 30% de la hauteur du parent
child: Container(color: [Link]),
)

ConstrainedBox - Contraintes personnalisées

16/31
ConstrainedBox(
constraints: BoxConstraints(
minWidth: 100,
maxWidth: 300,
minHeight: 50,
maxHeight: 200,
),
child: Container(color: [Link]),
)

Sous-partie 4 : Listes et défilement (ListView, GridView, ScrollController)

ListView - Liste verticale défilante

ListView simple :

ListView(
padding: [Link](8),
children: [
ListTile(
leading: Icon([Link]),
title: Text('Carte'),
subtitle: Text('Voir la carte'),
trailing: Icon(Icons.arrow_forward),
onTap: () {},
),
ListTile(
leading: Icon([Link]),
title: Text('Photos'),
),
ListTile(
leading: Icon([Link]),
title: Text('Téléphone'),
),
],
)

[Link] - Liste dynamique optimisée

Construit les éléments à la demande (lazy loading) :

17/31
[Link](
itemCount: 100, // Nombre d'éléments
itemBuilder: (context, index) {
return ListTile(
leading: CircleAvatar(child: Text('${index + 1}')),
title: Text('Élément $index'),
subtitle: Text('Description de l\'élément $index'),
onTap: () {
print('Élément $index cliqué');
},
);
},
)

[Link] - Avec séparateurs

[Link](
itemCount: 20,
itemBuilder: (context, index) {
return ListTile(
title: Text('Item $index'),
);
},
separatorBuilder: (context, index) {
return Divider(thickness: 1); // Ligne de séparation
},
)

Liste horizontale :

ListView(
scrollDirection: [Link],
children: [
Container(width: 160, color: [Link]),
Container(width: 160, color: [Link]),
Container(width: 160, color: [Link]),
],
)

SingleChildScrollView - Défilement d'un widget unique

Pour rendre un widget défilant sans utiliser ListView :

18/31
SingleChildScrollView(
child: Column(
children: [
Container(height: 300, color: [Link]),
Container(height: 300, color: [Link]),
Container(height: 300, color: [Link]),
],
),
)

GridView - Grille défilante

[Link] - Grille avec nombre de colonnes fixe

[Link](
crossAxisCount: 2, // 2 colonnes
crossAxisSpacing: 10, // Espacement horizontal
mainAxisSpacing: 10, // Espacement vertical
padding: [Link](10),
children: [Link](20, (index) {
return Card(
child: Center(
child: Text('Item $index'),
),
);
}),
)

[Link] - Grille avec taille maximale des éléments

[Link](
maxCrossAxisExtent: 150, // Largeur max de chaque élément
crossAxisSpacing: 10,
mainAxisSpacing: 10,
children: [
Container(color: [Link]),
Container(color: [Link]),
Container(color: [Link]),
],
)

[Link] - Grille dynamique optimisée

19/31
[Link](
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
crossAxisSpacing: 8,
mainAxisSpacing: 8,
childAspectRatio: 1, // Ratio largeur/hauteur
),
itemCount: 50,
itemBuilder: (context, index) {
return Card(
child: Center(child: Text('$index')),
);
},
)

ScrollController - Contrôle du défilement

class ScrollExample extends StatefulWidget {


@override
_ScrollExampleState createState() => _ScrollExampleState();
}

class _ScrollExampleState extends State<ScrollExample> {


final ScrollController _scrollController = ScrollController();
bool _showBackToTop = false;

@override
void initState() {
[Link]();
_scrollController.addListener(() {
// Détecte la position de défilement
if (_scrollController.offset > 200) {
setState(() {
_showBackToTop = true;
});
} else {
setState(() {
_showBackToTop = false;
});
}
});
}

@override
void dispose() {
_scrollController.dispose();
[Link]();
}

void _scrollToTop() {
_scrollController.animateTo(
0,
duration: Duration(milliseconds: 500),

20/31
duration: Duration(milliseconds: 500),
curve: [Link],
);
}

@override
Widget build(BuildContext context) {
return Scaffold(
body: [Link](
controller: _scrollController,
itemCount: 100,
itemBuilder: (context, index) {
return ListTile(title: Text('Item $index'));
},
),
floatingActionButton: _showBackToTop
? FloatingActionButton(
onPressed: _scrollToTop,
child: Icon(Icons.arrow_upward),
)
: null,
);
}
}

RefreshIndicator - Pull to refresh

21/31
RefreshIndicator(
onRefresh: () async {
// Logique de rafraîchissement
await [Link](Duration(seconds: 2));
// Recharger les données
},
child: [Link](
itemCount: 20,
itemBuilder: (context, index) {
return ListTile(title: Text('Item $index'));
},
),
)
Scrollbar - Barre de défilement
dartScrollbar(
thumbVisibility: true, // Toujours visible
child: [Link](
itemCount: 100,
itemBuilder: (context, index) {
return ListTile(title: Text('Item $index'));
},
),
)
ReorderableListView - Liste réorganisable
dartclass ReorderableExample extends StatefulWidget {
@override
_ReorderableExampleState createState() => _ReorderableExampleState();
}

class _ReorderableExampleState extends State<ReorderableExample> {


List<String> _items = [Link](10, (index) => 'Item $index');

@override
Widget build(BuildContext context) {
return ReorderableListView(
onReorder: (oldIndex, newIndex) {
setState(() {
if (newIndex > oldIndex) {
newIndex -= 1;
}
final item = _items.removeAt(oldIndex);
_items.insert(newIndex, item);
});
},
children: _items.map((item) {
return ListTile(
key: Key(item),
title: Text(item),
trailing: Icon(Icons.drag_handle),
);
}).toList(),
);
}
}

22/31
CustomScrollView avec Slivers - Défilement avancé

CustomScrollView(
slivers: [
// AppBar qui se rétracte
SliverAppBar(
expandedHeight: 200,
floating: false,
pinned: true,
flexibleSpace: FlexibleSpaceBar(
title: Text('Titre'),
background: [Link]('assets/[Link]', fit: [Link]),
),
),
// Liste
SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) => ListTile(title: Text('Item $index')),
childCount: 20,
),
),
// Grille
SliverGrid(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
),
delegate: SliverChildBuilderDelegate(
(context, index) => Card(child: Center(child: Text('$index'))),
childCount: 10,
),
),
],
)

23/31
Fiche de révision

Affichage de contenu visuel

Text - Afficher du texte

Text('Texte', style: TextStyle(fontSize: 20, color: [Link]))

textAlign : Alignement (left, center, right, justify)

maxLines : Nombre de lignes max

overflow : Gestion du débordement (ellipsis, clip, fade)

RichText : Combiner plusieurs styles dans un texte

Icon : Icônes Material Design

Icon([Link], size: 30, color: [Link])

Image : Afficher des images

[Link]() : Depuis assets

[Link]() : Depuis URL

[Link]() : Depuis fichier

BoxFit : cover, contain, fill, fitWidth, fitHeight

CircleAvatar : Image/texte circulaire (photos de profil)

Interaction et boutons

Types de boutons

ElevatedButton : Bouton élevé avec fond


TextButton : Bouton plat sans fond
OutlinedButton : Bouton avec bordure
IconButton : Bouton icône
FloatingActionButton : Bouton d'action flottant

Détection de gestes

GestureDetector : onTap, onDoubleTap, onLongPress, onPan, onScale


InkWell : Zone cliquable avec effet d'encre Material

StatefulWidget

Widget avec état mutable


Composé de 2 classes : Widget + State
setState() : Déclenche reconstruction du widget

24/31
Cycle de vie : initState() → build() → didUpdateWidget() → dispose()

Widgets de formulaire

TextField : Champ de saisie + TextEditingController


Checkbox : Case à cocher
Radio : Boutons radio
Switch : Interrupteur
CheckboxListTile / RadioListTile : Avec label intégré

Positionnement avancé
Stack : Empiler des widgets

Stack(children: [fond, milieu, premier_plan])

Positioned : Position absolue dans Stack

Positioned(top: 10, left: 20, child: Widget())

[Link]() : Remplit tout l'espace

Align : Aligner dans conteneur

[Link], center, bottomRight, etc.


Alignment(x, y) : x et y entre -1 et 1

Wrap : Disposition avec retour à la ligne

spacing : Espacement horizontal


runSpacing : Espacement vertical

Expanded / Flexible : Distribution d'espace

Expanded : Remplit l'espace (flex)


Flexible : Peut être plus petit

LayoutBuilder : Design responsive

LayoutBuilder(builder: (context, constraints) {


if ([Link] > 600) { /* layout large */ }
else { /* layout petit */ }
})

Autres widgets

AspectRatio : Maintenir ratio


FractionallySizedBox : Taille fractionnelle du parent
ConstrainedBox : Contraintes min/max

25/31
Listes et défilement

ListView : Liste verticale défilante

ListView() : Liste simple

[Link]() : Construction dynamique optimisée (lazy loading)

[Link]() : Avec séparateurs

scrollDirection: [Link] : Liste horizontale

SingleChildScrollView : Rendre un widget défilant

GridView : Grille défilante

[Link](crossAxisCount: 2) : Nombre de colonnes fixe


[Link](maxCrossAxisExtent: 150) : Taille max des éléments
[Link]() : Construction dynamique

ScrollController : Contrôler le défilement

ScrollController _controller = ScrollController();


_controller.animateTo(0) // Scroller vers position
_controller.offset // Position actuelle
_controller.addListener() // Écouter le scroll

Widgets supplémentaires

RefreshIndicator : Pull to refresh


Scrollbar : Barre de défilement visible
ReorderableListView : Liste réorganisable
CustomScrollView : Défilement avancé avec Slivers
SliverAppBar : AppBar qui se rétracte

ListTile : Élément de liste standard

ListTile(
leading: Icon(),
title: Text(),
subtitle: Text(),
trailing: Icon(),
onTap: () {},
)

Points clés à retenir

Tout est widget en Flutter


setState() obligatoire pour mettre à jour l'UI dans StatefulWidget
Builder pour listes/grilles optimise les performances (lazy loading)
Stack + Positioned pour superposition

26/31
LayoutBuilder pour responsive design
ScrollController doit être dispose() pour éviter les fuites mémoire
Wrap vs Row : Wrap gère le retour à la ligne automatiquement

27/31
QCM

Q1 : Quelle propriété du widget Text permet de gérer le débordement du texte ?

a) textOverflow
b) overflow
c) clip
d) maxLines
e) ellipsis

Q2 : Quel mode BoxFit remplit complètement la boîte en coupant l'image si nécessaire ?

a) [Link]
b) [Link]
c) [Link]
d) [Link]
e) [Link]

Q3 : Quel widget permet d'afficher une image depuis les assets du projet ?

a) [Link]()
b) [Link]()
c) [Link]()
d) [Link]()
e) AssetImage()

Q4 : Quel type de bouton Material a une élévation et un fond coloré par défaut ?

a) TextButton
b) OutlinedButton
c) IconButton
d) ElevatedButton
e) FlatButton

Q5 : Quelle méthode est essentielle pour mettre à jour l'interface d'un StatefulWidget ?

a) update()
b) rebuild()
c) setState()
d) refresh()
e) notifyListeners()

Q6 : Dans le cycle de vie d'un StatefulWidget, quelle méthode est appelée en premier lors de
la création ?

a) build()
b) initState()
c) didChangeDependencies()
d) createState()
e) dispose()

28/31
Q7 : Quel widget permet de détecter un appui long, un double tap et un glissement ?

a) InkWell
b) GestureDetector
c) TouchDetector
d) TapDetector
e) ClickDetector

Q8 : Quel widget permet de superposer des éléments les uns sur les autres ?

a) Layer
b) Overlay
c) Stack
d) Pile
e) ZIndex

Q9 : Comment positionner un widget de manière absolue dans un Stack ?

a) Avec le widget Absolute


b) Avec le widget Positioned
c) Avec le widget Fixed
d) Avec la propriété position
e) Ce n'est pas possible

Q10 : Quel widget permet une disposition qui passe automatiquement à la ligne suivante ?

a) Row
b) Column
c) Wrap
d) Flow
e) Flex

Q11 : Quelle différence principale existe-t-il entre Expanded et Flexible ?

a) Aucune différence
b) Expanded force le remplissage de l'espace, Flexible peut être plus petit
c) Flexible est plus rapide qu'Expanded
d) Expanded ne fonctionne que dans Row
e) Flexible ne fonctionne que dans Column

Q12 : Quel widget permet d'adapter le layout en fonction de la taille de l'écran ?

a) MediaQuery
b) ResponsiveBuilder
c) LayoutBuilder
d) ScreenBuilder
e) AdaptiveLayout

Q13 : Quelle méthode de ListView est optimisée pour de longues listes avec construction à la
demande ?

a) ListView()

29/31
b) [Link]()
c) [Link]()
d) [Link]()
e) [Link]()

Q14 : Quel widget permet de rendre un widget unique défilant sans utiliser ListView ?

a) ScrollView
b) Scrollable
c) SingleChildScrollView
d) ScrollWidget
e) ScrollContainer

Q15 : Dans [Link], que représente le paramètre crossAxisCount ?

a) Le nombre total d'éléments


b) Le nombre de lignes
c) Le nombre de colonnes
d) L'espacement entre éléments
e) La hauteur de chaque élément

Q16 : Quel objet permet de contrôler programmatiquement le défilement d'une liste ?

a) ListController
b) ScrollManager
c) ScrollController
d) ListManager
e) ScrollHandler

Q17 : Quel widget permet d'ajouter la fonctionnalité "pull to refresh" ?

a) PullToRefresh
b) RefreshIndicator
c) RefreshWidget
d) ReloadIndicator
e) UpdateIndicator

Q18 : Que doit-on faire avec un TextEditingController ou ScrollController avant la destruction


du widget ?

a) Le réinitialiser avec reset()


b) Le libérer avec dispose()
c) Le sauvegarder avec save()
d) Le fermer avec close()
e) Rien, c'est automatique

Q19 : Quel widget affiche une image ou du texte dans un cercle, parfait pour les avatars ?

a) CircularImage
b) RoundedImage
c) CircleAvatar

30/31
d) AvatarWidget
e) ProfilePicture

Q20 : Quelle propriété de Stack définit l'alignement par défaut de ses enfants ?

a) defaultAlignment
b) childAlignment
c) alignment
d) stackAlignment
e) position

Réponses du QCM

Q1 : b
Q2 : c
Q3 : c
Q4 : d
Q5 : c
Q6 : b
Q7 : b
Q8 : c
Q9 : b
Q10 : c
Q11 : b
Q12 : c
Q13 : b
Q14 : c
Q15 : c
Q16 : c
Q17 : b
Q18 : b
Q19 : c
Q20 : c

31/31

Vous aimerez peut-être aussi