Урок 3. ListView бесконечный прокручиваемый список

Поділитись

Виджет-класс ListView позволяет создавать конечные и бесконечные списки виджетов и делает их прокручиваемыми, если они не помещаются на экране или в отведенной для них области.

Под бесконечным списком мы будем понимать список элементов, который пополняется по мере необходимости, в нашем уроке – когда существующие элементы уже отображены. В мобильных приложениях такие списки повсюду: новостные ленты, списки сообщений, фотогалереи и т.п.

Класс ListView имеет несколько конструкторов, в этом уроке мы рассмотрим два из трех.

1. Простой список с помощью конструктора ListView() – по умолчанию

Создадим простой список текстовых элементов с использованием класса ListView.

Конструктор по умолчанию ListView() строит список из заданных элементов в параметре children.

Конструктор по умолчанию 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 для создания новых элементов списка при прокрутке, позволяет создавать бесконечные списки виджетов.

Конструктор ListView.builder() выводит элементы списка по требованию

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] – возвращает значение из массива

Рекомендуем изучить сообщения, которые выводятся в консоль:

Бесконечный список ListView.builder с разделителями
Сообщения консоли при добавлении нового элемента в список ListView

По мере того как Вы будете прокручивать список в эмуляторе или на смартфоне, список будет создавать новые элементы списка, и в консоли будут появляться новые сообщения.

4. Задание для практики: бесконечный список степени числа 2 (два)

  1. Измените строковый список List<String> _array = []; на числовой List<int> _array = [];
  2. Попробуйте изменить приведенный выше код для вывода бесконечного списка степени числа 2 с помощью математической функции pow() и без нее.
  3. Результат должен быть похожим как на изображении ниже
      
  4. Можно ли сделать на Flutter бесконечный список для степени числа 2 с помощью типа int или double?
  5. Какие бесконечные списки Вы можете придумать?

Для выполнения задания вам понадобится:

  • 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, в теме письма обязательно указывайте «Урок № 3».


Поділитись