Динамическое создание ListView

Последнее обновление: 19.02.2021

В прошлой теме был рассмотрен пример создания простейшего списка ListView:

import 'package:flutter/material.dart';

const double textSize = 22;
void main() {
  runApp(MaterialApp(
      home:  Scaffold(
        body: ListView(
          padding: const EdgeInsets.all(8),
          children:[
            Text("Tom", style: TextStyle(fontSize: textSize)),
            Text("Alice", style: TextStyle(fontSize: textSize)),
            Text("Bob", style: TextStyle(fontSize: textSize)),
            Text("Sam", style: TextStyle(fontSize: textSize)),
            Text("Kate", style: TextStyle(fontSize: textSize)),
          ],
        ),
        appBar: AppBar(title: Text("METANIT.COM")),)
  ));
}

Конструктор по умолчанию класса List, который использован в примере выше, подходит для создания списков с небольшим количеством элементов, поскольку в данном случае нам приходится настраивать каждый элемент списка. Однако даже в примере выше с небольшим количеством элементов мы видим, что все элементы Text отличаются только текстом. И было бы неплохо, если бы мы просто могли бы один раз определить виджет Text и каким-то образом передать ему все необходимые строки для отображения. И в этом случае мы можем использовать другой конструктр класса ListView - ListView.builder().

ListView.builder() в качестве параметра itemBuilder принимает объект IndexedWidgetBuilder, который создает элементы списка. Этот конструктор более удобен для создания больших списков.

Например, переделаем предыдущий пример с применением конструктора ListView.builder():

import 'package:flutter/material.dart';

const List<String> users = <String>["Tom", "Alice", "Bob", "Sam", "Kate"];
void main() {
  runApp(MaterialApp(
      home:  Scaffold(
        body: ListView.builder(
            padding: const EdgeInsets.all(8),
            itemCount: users.length,
            itemBuilder: (BuildContext context, int index) {
              return Text(users[index], style: TextStyle(fontSize: 22));
            }
        ),
        appBar: AppBar(title: Text("METANIT.COM")),)
  ));
}

Объект IndexedWidgetBuilder, который передается параметру itemBuilder, по сути представляет функцию Widget Function(BuildContext context, int index), которая получает контекст виджета, а также индекс и возвращает созданный виджет. Что передается в качестве индекса?

Здесь для ListView также устанавливается количество элементов с помощью параметра itemCount - оно равно количеству объектов в списке users: itemCount: users.length (в данном случае 5 элементов). В итоге itemBuilder будет последовательно перебирать числа от 0 до users.length, которые передаются в параметр index, и таким образом для каждого передаваемого индекса создавать виджет Text и передавать в виджет значение users[index].

Фактически по своему действию данную функцию можно сравнивать с циклом, в котором для каждого индекса создается свой виджет Text. В итоге мы получим следующий список ListView:

ListView.builder и IndexedWidgetBuilder в Flutter и Dart

При этом мы можем использовать несколько источников для создания ListView:

import 'package:flutter/material.dart';

const List<String> users = <String>["Tom", "Alice", "Bob", "Sam", "Kate"];
const List<String> companies = <String>["Microsoft", "Google", "Apple", "JetBrains", "Amazon"];
void main() {
  runApp(MaterialApp(
      home:  Scaffold(
        body: ListView.builder(
            padding: const EdgeInsets.all(8),
            itemCount: users.length,
            itemBuilder: (BuildContext context, int index) {
              return Container(
                padding: EdgeInsets.symmetric(vertical: 10),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text(users[index], style: TextStyle(fontSize: 22)),
                    Text("Место работы: ${companies[index]}", style: TextStyle(fontSize: 18))
                  ],
                )
              );
            }
        ),
        appBar: AppBar(title: Text("METANIT.COM")),)
  ));
}

В данном случае есть два списка List - условно один для пользователей, а другой для компаний. При создании ListView функция itemBuilder для каждого элемента ListView генерирует виджет Container, который включает два виджета Text: один выводит имя пользователя, а другой - название компании.

ListView.builder и наполнение ListView в Flutter и Dart

То есть в данном случае функция из itemBuilder сначала выбирает первый элемент из списка users и первый элемент из списка companies, потому выбирает по второму элементу из этих списков и так далее.

Правда, здесь надо учитывать, что в обоих списках должно быть не меньше элементов, чем указано для параметра itemCount виджета ListView.

Естественно мы можем передавать в список и более сложные объекты:

import 'package:flutter/material.dart';

class User{
  String name;
  int age;
  User(this.name, this.age);
}
final List<User> users = <User>[User("Tom", 36), User("Alice", 31), User("Bob", 41), User("Sam", 28)];

void main() {
  runApp(MaterialApp(
      home:  Scaffold(
        body: ListView.builder(
            padding: const EdgeInsets.all(8),
            itemCount: users.length,
            itemBuilder: (BuildContext context, int index) {
              return Container(
                padding: EdgeInsets.symmetric(vertical: 10),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text(users[index].name, style: TextStyle(fontSize: 22)),
                    Text("Возраст: ${users[index].age}", style: TextStyle(fontSize: 18))
                  ],
                )
              );
            }
        ),
        appBar: AppBar(title: Text("METANIT.COM")),)
  ));
}

В данном случае для каждого объекта User в списке users создается отдельный элемент в ListView:

Динамическое создание ListView в Flutter и Dart
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850