Tout ce que vous devez savoir sur les ListView Flutter


Avatar de Pierre Courtois

Dans certain cas, il peut être nécessaire d’afficher à l’écran des listes d’items. Pour cela, vous allez pouvoir utiliser le widget Listview. Comment le mettre en place et rendre votre liste agréable visuellement ? Tout cela est expliqué sur Tuto Flutter.fr, ainsi que bien d’autres choses sur comment coder avec Flutter.


Ordinateur et widgets autour

Comment créer une ListView dans Flutter ?

Le widget ListView est un outil de Flutter permettant de créer une liste d’éléments que l’utilisateur peut faire défiler. Par exemple, la ListView peut être utilisée pour créer une liste de contacts, de produits ou d’images. Vous pouvez ensuite la faire défiler soit de haut en bas, soit de gauche à droite, comme un carrousel d’images.

La ListView se compose d’un paramètre children[], qui contient des widgets de type ListTile. Ces ListTiles représentent les différents items de votre liste, et peuvent être personnalisés pour les rendre plus esthétiques.

Construire une ListView avec des ListTiles figés

La façon la plus simple de créer une ListView est d’utiliser des ListTiles fixes. Cela signifie que les éléments de la liste et leur contenu ne pourront pas changer de manière dynamique. Ce type de ListView est donc idéal pour mettre en place des éléments de votre application qui ne seront pas amenés à bouger. Voici un exemple fourni par Flutter : 

Container(
  heigth: Media.of(context).size.heigth * 0.3, 
  width: Media.of(context).size.width * 0.9,
  child : 
 ListView(
  children: const <Widget>[
    ListTile(
      leading: Icon(Icons.map),
      title: Text('Map'),
    ),
    ListTile(
      leading: Icon(Icons.photo_album),
      title: Text('Album'),
    ),
    ListTile(
      leading: Icon(Icons.phone),
      title: Text('Phone'),
    ),
  ],
 ),
),

Cette solution est la plus simple à mettre en place si vous savez à l’avance combien d’items pour aurez dans votre ListView. Par exemple, vous pouvez l’utiliser pour un menu, comme dans l’exemple que je vous ai fourni. 

Construire une ListView avec la méthode builder et un widget List

La deuxième manière de créer une ListView est de la construire à partir d’une variable de type List. En ajoutant la méthode .builder() à votre ListView, vous pouvez générer automatiquement un élément de la liste (comme un ListTile) pour chaque élément de votre liste de données : 

List<String> menuItems = [“Map”, “Album”, “Phone”];
List<IconData> menuIcons = [Icons.map, Icons.photo_album, Icons.phone]

Container(
  heigth: Media.of(context).size.heigth * 0.3, 
  width: Media.of(context).size.width * 0.9,
  child : ListView.builder(
  itemCount: menuItems.length,
  itemBuilder: (context, index) {
	return ListTile(
          leading: Icon(menuIcons[index]),
          title : Text(“${index + 1} ${menuItems[index]}“)
    )
   }
),

Avec cette méthode, il n’est pas nécessaire de créer chaque ListTile à la main. La méthode builder() permet de construire un nombre d’items égal au nombre d’éléments présents dans la liste passée en argument. Par exemple, si la liste menuItems a une longueur de 3, la ListView sera alors composée de 3 ListTiles. L’index est ensuite utilisé pour attribuer une icône, un numéro et un titre à chaque widget. Par exemple, le premier élément aura une icône Icons.map (menuIcons[0]), le numéro 1 (0 + 1) et un titre « Map » (menuItems[0]).

Il est important que la valeur de itemCount soit inférieure ou égale à la longueur de la liste utilisée. Si itemCount est plus grand que la longueur de la liste, un message d’erreur apparaîtra. Par exemple, si itemCount a une valeur de 4 mais que la liste menuTags ne contient que 3 éléments, l’application plantera lorsqu’elle tentera d’accéder à menuTags[3], car cet élément n’existe pas.

Construire sa ListView avec ListView.builder et une Map

Il est possible de construire une ListView à partir d’une variable de type Map en stockant les clés et les valeurs dans deux listes distinctes. Voici comment procéder :

Map<dynamic, dynamic> mapChiffres = {"zero": 0, "un": 1, "deux": 2};
List<String> keysLists = mapChiffres.keys.toList();
List<String> valuesLists = mapChiffres.values.toList();

Ensuite, utilisez l’une de ces deux listes pour construire votre ListView.builder() et les éléments des deux listes pour vos ListTiles.

Construire sa ListView avec ListView.builder et Firebase

Il est possible de récupérer des informations depuis Firebase et de les utiliser pour construire une ListView dans Flutter.

À partir d’une liste contenue dans un document

Pour créer des ListTiles à partir d’une liste stockée dans un document Firebase, suivez ces étapes :

  1. Récupérez le document en utilisant async et await et stockez-le dans une variable :
var myDoc = await Firestore.instance.collection('collection 1').document('document 1').get();

2. Utilisez la variable créée pour extraire la liste souhaitée :

List<dynamic> maListe = myDoc.data()["Ma liste"]; 

3. Maintenant, vous pouvez utiliser votre liste pour construire une ListView.builder() et utiliser maList.length comme argument pour itemCount

Container(
  heigth: Media.of(context).size.heigth * 0.3, 
  width: Media.of(context).size.width * 0.9,
  child : ListView.builder(
  itemCount: maListe.length,
  itemBuilder: (context, index) {
	return ListTile(
  title : Text(“${myDoc[index]}“)
    )
   }
  )
),

Il est crucial de réaliser la première étape avec une fonction asynchrone et d’utiliser await. Sinon, vous recevrez une erreur à l’étape 2, indiquant que l’opérateur [] n’est pas défini pour le type ‘Future<DocumentSnapshot<Map<String, dynamic>>’. Il est normal de trouver cela délicat au début, surtout sans l’utilisation d’un StreamBuilder. Ne vous découragez pas, cela peut prendre du temps pour s’y habituer, même jusqu’à 30 minutes parfois.

À partir d’une liste de documents

Vous pouvez également utiliser une liste de documents Firebase pour créer une ListView dans Flutter. Voici les étapes à suivre : 

  1. Créez une variable contenant un snapshot de votre collection : 
final _myCollection = FirebaseFirestore.instance.collection('Ma collection').snapshots();

2. Utilisez un StreamBuilder qui utilise votre snapshot comme paramètre :

StreamBuilder(
   stream: _Lists,
   builder:(context, AsyncSnapshot<QuerySnapshot> snapshot) {
  }
)

3. Dans le builder, créez une variable pour accéder à vos documents :

var docs = snapshot.data?.docs;

4. Toujours dans le builder, créez une ListView.builder() et utilisez la longueur de votre variable docs pour le paramètre itemCount :

return Container(
   child: ListView.builer(
        itemCounter: docs?.length,
        itemBuilder: (context, index) { }
)

5. Pour utiliser les informations de vos documents dans vos ListTiles, utilisez la variable docs que vous avez créée, suivie de l’index, puis du champ que vous souhaitez récupérer. Par exemple :

child: ListTile(
	title: Text(“${docs?[index]["Ma variable"]}”),
)

Personnaliser vos ListTiles

Le widget ListTile offre plusieurs paramètres pour personnaliser son apparence. Voici les plus utilisés :

leading : Zone la plus à gauche du ListTile. Peut être utilisée pour afficher une icône, par exemple ;

title : Donne un titre au ListTile. Vous pouvez y mettre autre chose que du texte, en l’enveloppant dans un Container() ;

subtitle : Donne un sous-titre au ListTile. Comme pour le titre, vous pouvez y mettre autre chose que du texte ;

trailing : Zone la plus à droite du ListTile. Utile pour placer un bouton, par exemple ;

scrollDirection : Définit l’axe de défilement de la liste, horizontal ou vertical ;

reverse : Inverse l’ordre des ListTiles (le dernier index apparaît en haut) ;

tileColor : Couleur du ListTile lorsqu’il n’est pas sélectionné ;

selectedTileColor : Couleur du ListTile lorsqu’il est sélectionné ;

hoverColor : Couleur lorsque le doigt ou la souris passe sur le ListTile ; 

textcolor : Couleur du texte du ListTile ; 

iconColor : Couleur des icônes du ListTile ; 

selectedColor : Couleur des icônes et des boutons lorsque le ListTile est sélectionné ; 

titleTextStyle : Style du texte du titre (police, taille, poids, etc.) ;

subtitleTextStyle : Style du texte du sous-titre (police, taille, poids, etc.) ;

leadingAndTrailingTextStyle : Style du texte des zones leading et trailing (police, taille, poids, etc.) ;

onTap() : Action déclenchée lors d’un clic sur le ListTile ;

onLongPress() : Action déclenchée lors d’un appui long sur le ListTile ;

Avec ces paramètres, vous disposez des bases pour personnaliser vos ListTiles. Laissez libre cours à votre créativité !

Faire des ListTiles différents dans la même ListView

Le widget ListView.builder() génère plusieurs fois le même ListTile dans le builder. Pour créer des variations au sein de la même liste, utilisez l’index pour présenter un élément différent à chaque itération. Par exemple, pour des arrière-plans différents pour chaque item, créez une liste de couleurs et utilisez myColor[index] comme argument de tileColor.

Faire des ListTiles arrondis

Il existe plusieurs façons de créer des ListTiles arrondis. Une méthode courante consiste à les placer dans des Containers avec une forme arrondie définie par le paramètre decoration, puis BorderRadius.circular(). Vous pouvez également ajouter une ombre sous votre Container pour le mettre en évidence. Par exemple :

Container(
   height: MediaQuery.of(context).size.height * 0.35,
    width: MediaQuery.of(context).size.width * 0.6,
    decoration: BoxDecoration(
    boxShadow: const [
        BoxShadow(
            color: Color.fromARGB(255, 254, 234, 161),
            offset: Offset(5, 0),
        )
         ],
        border: Border.all(
        width: 2,
        color: const Color.fromARGB(255, 24, 83, 79)),
        borderRadius: BorderRadius.circular(10),
        color: const Color.fromARGB(255, 254, 234, 161),
    ),                                                                               child: ListTile()
)

Avec cette technique, la couleur du ListTile va être définie par la couleur du Container() et non pas celle de tileColor.

Ajouter un espace entre les ListTiles

Pour ajouter des espaces entre les éléments de votre ListView, vous pouvez utiliser la méthode .separated() plutôt que .builder(). Les deux méthodes sont similaires, mais la première inclut un paramètre separatorBuilder. Voici un exemple de son utilisation dans votre ListView : 

separatorBuilder: (context, index) => SizedBox(
   heigth: MediaQuery.of(context).size.heigth * 0.04,
),

En utilisant ce paramètre, vous pouvez insérer un espace, par exemple une SizedBox, d’une hauteur de 0,04 fois la hauteur de l’écran, entre chaque ListTile de votre liste.

Avatar de Pierre Courtois