Kleine Listen für Flutter

Listen für Flutter

In diesem Post werde ich mir das ListView(...) Widget von Flutter anschauen.

Daten werden häufig in Form einer Liste dargestellt. In diesem Blog hatten wir schon das Column Widget(...)  und das Row Widget(...) im Einsatz.

Du weißt wahrscheinlich schon, das Du mit dem Column Widget Inhalte in der vertikalen Ebene anordnen kannst, während das Row Widget, das gleiche auf der horizontalen Ebene vornimmt.

Sobald Du an den Einsatz eines dieser Widgets denkst, sollte immer die Frage beantwortet sein, ob dein Inhalt die Grenzen des Bildschirms in der entsprechenden Richtung überschreiten wird. Abhängig von der Antwort ergeben sich andere Problemstellungen.

ListView ist etwas für bequeme

Der Zweck eines Frameworks wie Flutter ist es Dinge einfacher zu machen. So kann man mit dem Column und Row Widget vieles, was mit dem ListView Widget möglich ist, auch ohne dieses erreichen. Man sollte sich aber immer die Frage stellen, ob sich der Aufwand lohnt.

Um das Widget zu testen benutze ich folgenden Code:

import 'package:flutter/material.dart';

void main(){
  runApp(const MeineApp());
}

class MeineApp extends StatelessWidget {
  const MeineApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: MeineHomePage(),
    );
  }
}
class MeineHomePage extends StatelessWidget {
  const MeineHomePage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('List View Demo'),
      ),
      body: erzeugeListe() ,
    );
  }
}

Oben sollte nichts wirklich überraschen. Ich verwende eine MaterialApp inklusive Scaffold. Ohne Scaffold würden wir eine Fehlermeldung bekommen, da das ListView(...) Widget ein sogenanntes, scrollbares Widget ist. Das heisst unsere Liste könnte mehr Einträge haben, als auf dem Bildschirm darstellbar sind. Der Anwender kann also die Liste scrollen, um auf die nicht dargestellten Listeneinträge zugreifen zu können.

Der body: Eintrag unseres Scaffolds ruft die Funktion erzeugeListe(...) auf. Darin generiere ich die eigentliche Liste:


Widget erzeugeListe(){
  var liste = ListView(
    children: const [
      ListTile(
        leading: Icon(Icons.access_alarm),
        title: Text('Alarm !!'),
        subtitle:  Text('Der Alarm ist gesetzt'),
        trailing: Icon(Icons.account_box),
      )
    ],
  );
  return liste;
}

Die Funktion retourniert ein Widget. ListView(...) selbst können wir eine Liste von Widgets übergeben. Dabei ist ListTile(...) eines in diesem Zusammenhang am meisten verwendeten Widgets. Der Code oben zeigt den theoretischen Standard Aufbau: Ein Icon ganz links, anschliessend ein Titel und Untertitel, abschließend wieder ein Icon ganz rechts.

List View Demo eins


Theoretisch deshalb, da ListTile zum Beispiel für leading: ein Widget erwartet. Das kann ein Icon sein, muss es aber nicht. Das gleiche gilt auch für trailing: .

Ein beliebtes Widget in diesem Zusammenhang ist das CircleAvatar(...) Widget :


Widget erzeugeListe(){
  var liste = ListView(
    children: const [
      ListTile(
        leading: Icon(Icons.access_alarm),
        title: Text('Alarm !!'),
        subtitle:  Text('Der Alarm ist gesetzt'),
        trailing: Icon(Icons.account_box),
      ),
      ListTile(
        leading: CircleAvatar(
          backgroundImage: AssetImage('lib/bilder/officeWorker.png'),
        ),
        title: Text('Alarm !!'),
        subtitle:  Text('Der Alarm ist gesetzt'),
        trailing: Icon(Icons.account_box),
      )
    ],
  );
  return liste;
}

Es wird zum Beispiel gerne in Kontaktlisten verwendet:

List View Demo zwei


Variante von ListView


ListView ist im Einsatz also sehr flexibel. Dabei ist dieses Widget nicht auf eine Achse festgelegt ! Wenn Du die Dokumentation zu ListView liest, wirst Du auf den Parameter scrollDirection: stossen. Ihm können wir die Ausrichtung übergeben, also Axis.vertical oder Axis.horizontal

Nur leider funktioniert, das mit dem Code oben nicht. ListTile(...) ist so ausgelegt, den kompletten Raum auf der horizontalen Ebene einzunehmen ! Doch wir benötigen ListTile(...) nicht unbedingt:


Widget erzeugeListe2(){
    var liste = ListView(
        scrollDirection: Axis.horizontal,
        children: <Widget>[
          Container(
            width: 160.0,
            color: Colors.red,
          ),
          Container(
            width: 160.0,
            color: Colors.blue,
          ),
          Container(
            width: 160.0,
            color: Colors.green,
          ),
          Container(
            width: 160.0,
            color: Colors.yellow,
          ),
          Container(
            width: 160.0,
            color: Colors.orange,
          ),
        ],
      );
    return liste;
  }

Die Funktion erzeugeListe2(...) verzichtet gänzlich auf ListView und verwendet stattdessen das Container(...) Widget. 


Wenn ich die Funktion einfach so in den Code einfügte, würden die Farbbalken die komplette Höhe des Bildschirms einnehmen. Das ist dem Verhalten des Containers geschuldet, der in diesem Beispiel kein child: Eintrag besitzt. Das umgehen wir durch eine kleine Änderung am Hauptcode:


class MeineHomePage extends StatelessWidget {
  const MeineHomePage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('List View Demo'),
      ),
      body: Container(child: erzeugeListe2(),
      height: 200.0,) ,
    );
  }
}

Neu wird die Listen Funktion nicht direkt an body: übergeben. Stattdessen ist sie ein child: eines Container(...) Widgets, welches mit Angaben für Höhe und Breite ausgestattet ist.

Und noch mehr Varianten von ListView


Bis jetzt haben wir einzig ListView(...) getestet. Dieses Widget eignet sich für eine begrenzte Anzahl von Kinder Widgets. Werden es zu viele, leidet die Leistung der Anwendung darunter ! Das hat den Hintergrund, das dieses Widget alle Listeneinträge generiert, egal ob sie aktuell auf dem Bildschirm zu sehen sind oder nicht.

ListView.builder(...) : Diese Variante, dieser Konstruktor, schafft hier Abhilfe.  Er ist geeignet für eine grosse Anzahl von Listeneinträgen, da er nur die aktuell sichtbaren erstellt.

ListView.separated(...) : Eine Variante, mit der man eine visuelle Trennung der einzelnen Listenelemente vornehmen kann. Dieses Widget ist nur für eine begrenzte Anzahl von Einträgen zu empfehlen.

ListView.custom(...) : Sollte man noch mehr Kontrolle über die Listeneinträge benötigen, kann man diese Variante wählen.

Im nächsten Post werden wir uns ListView.builder näher ansehen. Bis bald 😀 !

Kommentare

Beliebte Posts aus diesem Blog

Flutter und JSON

Flutter BloC Pattern 1

Dart Basic: Parameter in Funktionen