Урок 3. ListView бесконечный прокручиваемый список
Егор Долгов · 05.07.2019Виджет-класс ListView позволяет создавать конечные и бесконечные списки виджетов и делает их прокручиваемыми, если они не помещаются на экране или в отведенной для них области.
Под бесконечным списком мы будем понимать список элементов, который пополняется по мере необходимости, в нашем уроке – когда существующие элементы уже отображены. В мобильных приложениях такие списки повсюду: новостные ленты, списки сообщений, фотогалереи и т.п.
Класс ListView имеет несколько конструкторов, в этом уроке мы рассмотрим два из трех.
1. Простой список с помощью конструктора ListView() – по умолчанию
Создадим простой список текстовых элементов с использованием класса ListView .
Конструктор по умолчанию ListView() строит список из заданных элементов в параметре children .
import 'package:flutter/material.dart';
void main() => runApp(
new MaterialApp(
debugShowCheckedModeBanner: false,
home: new Scaffold(
body: new ListView(children: [
new Text('0000'),
new Divider(),
new Text('0001'),
new Divider(),
new Text('0010'),
])// ListView
)// Scaffold
)// MaterialApp
);
- new Text('') – создание текстового виджета
- new Divider() – виджет-разделитель, отображается как горизонтальная или вертикальная полоса (в зависимости от направления расположения виджетов)
2. Бескочнечный список с помощью ListView.builder() – список по требованию
Конструктор ListView.builder() выводит элементы списка по требованию – вызывает функцию в параметре itemBuilder для создания новых элементов списка при прокрутке, позволяет создавать бесконечные списки виджетов.
import 'package:flutter/material.dart';
void main() => runApp(
new MaterialApp(
debugShowCheckedModeBanner: false,
home: new Scaffold(
body: new ListView.builder(
itemBuilder: (context, index) {
return new Text('строка $index');
},
)// ListView.builder
)// Scaffold
)// MaterialApp
);
- itemBuilder – обязательный параметр для конструктора ListView.builder() , в качестве значения он принимает функцию, которая возвращает виджет-элемент.
- index – переменная типа int , принимает значение от 0 до N, где N – натуральное число.
- return new Text('строка $index'); – возвращает текстовый виджет со значением index .
Функция в itemBuilder вызывается каждый раз с новым значением index , когда нужно заполнить экран или область которую занимает ListView .
3. Реальное использование ListView.builder() для бесконечных списков
В жизни для создания больших списков используется более сложная конструкция, чем мы описали выше.
Нам понадобится создать класс MyBody от супер-класса StatefulWidget (который мы рассмотрели в прошлом уроке ). MyBody будет вызывать функцию состояния через createState() => new MyBodyState();
Поэтому нам понадобится еще объявить класс MyBodyState от супер-класса State .
В классе MyBodyState мы объявим List<String> array = []; скрытое поле-массив, в котором будут текстовые значения для элемента списка класса Text() . А функция build() будет возвращать список ListView.builder .
import 'package:flutter/material.dart';
class MyBody extends StatefulWidget {
@override
createState() => new MyBodyState();
}
class MyBodyState extends State<MyBody> {
List<String> _array = [];
@override
Widget build(BuildContext context) {
return new ListView.builder(itemBuilder: (context, i){
print('num $i : нечетное = ${i.isOdd}');
if(i.isOdd) return new Divider();
final int index = i ~/ 2;
print('index $index');
print('length ${_array.length}');
if (index >= _array.length) _array.addAll(['$index', '${index + 1}', '${index + 2}']);
return new ListTile(title: new Text(_array[index]));
});
}
}
void main() => runApp(
new MaterialApp(
debugShowCheckedModeBanner: false,
home: new Scaffold(body: new Center(child: new MyBody(),))
)
);
Рассмотрим подробно функцию build() в нашем классе MyBodyState:
- return new ListView.builder(itemBuilder: (context, i){ – Сама функция build в нашем примере возвращает список ListView с конструктором по требованию .builder
- print('num $i : нечетное = ${i.isOdd}'); – выводим в консоль строку значение переменной i , пример вывода: num 0 : нечетное = false num 1 : нечетное = true num 2 : нечетное = false и т.д.
- if(i.isOdd) return new Divider(); – если значение переменной i нечетное, то возвращается виджет-разделитель и на этом выполнение функции для данного i завершается.
- final int index = i ~/ 2; – объявляем переменную index типа int , в качестве значения, результат целочисленного деления переменной i на 2. На нечетном значении переменной i = {1, 3, 5, 7, 9, 11, …} мы создает виджет разделитель а на четном значении i = {0, 2, 4, 6, 8, 10, 12, …} виджет строку. Для того чтобы в текстовом виджете использовать индексы по порядку а не только четные значения i , мы используем целочисленное деление от четных значений i и получаем index = {0, 1, 2, 3, 4, 5, 6, …}
- print('index $index'); – выводим в консоль значение переменной index , пример вывода: index 0 index 1 index 2 и т.д.
- print('length ${ array.length}'); – выводим в консоль длину массива array объявленного в классе MyBodyState , пример вывода: length 0 length 3 length 6 и т.д.
- if (index >= array.length) array.addAll(['$index', '${index + 1}', '${index + 2}']); if (index >= array.length) – если значение index больше или равно числу элементов в массиве array_array.addAll([]) – добавить в массив array все элементы из списка []'$index' – строковое значение переменной index'${index + 1}' – строковое значение переменной index увеличенное на единицу
В данном примере мы в массив array добавляем сразу три новых элемента, по аналогии как это может происходить при реальном получение данных с сервера. Так, например, получая список новостей с сервера мы загружаем их по 20 штук сразу (пример), а потом при необходимости загружаем следующие 20. Загружать все новости, особенно если их очень много, нет никакого смысла, т.к. предполагаем, что пользователь прочтет от 1 до 20 новости наверняка, и, если нужно, мы загрузим остальные.
В нашем примере мы могли написать так: array.add('$index'); – добавить один элемент в массив.
- return new ListTile(title: new Text( array[index])); – результат функции, мы возвращаем виджет элемент-списка с виджетом текста return new Text( array[index]); – можно было сделать так, но с классом ListTile элементы нашего списка выглядят привлекательнее array[index] – возвращает значение из массива
Рекомендуем изучить сообщения, которые выводятся в консоль:
По мере того как Вы будете прокручивать список в эмуляторе или на смартфоне, список будет создавать новые элементы списка, и в консоли будут появляться новые сообщения.
4. Задание для практики: бесконечный список степени числа 2 (два)
- Измените строковый список List<String> array = []; на числовой List<int> array = [];
- Попробуйте изменить приведенный выше код для вывода бесконечного списка степени числа 2 с помощью математической функции pow() и без нее.
- Результат должен быть похожим как на изображении ниже
- Можно ли сделать на Flutter бесконечный список для степени числа 2 с помощью типа int или double ?
- Какие бесконечные списки Вы можете придумать?
Для выполнения задания вам понадобится:
- import 'dart:math'; подключить библиотеку с математическими функциями
- pow(3, 2) – функция возведение числа в степень (3 в степени 2)
- pow(3, 2).toString() – вернет результат функции в строковом виде
- index.toDouble() – преобразовать в тип double
- pow(2.0, 3).toStringAsFixed(0 ) – преобразовать значение функции типа double с точности до целого (чтобы не выводить значение с точкой и нулем)
Ваши вопросы и ответы в виде кода программы присылайте на нашу почту [contact@flutter.ru](mailto:contact@flutter.ru?subject=Урок № 3), в теме письма обязательно указывайте «Урок № 3».