Элементы управления прокруткой Flutter -> ListView

Flutter

во флаттереListViewявляется одним из наиболее часто используемых прокручиваемых компонентов,
ЭтоВсе подкомпоненты могут быть расположены линейно в одном направлении, а также поддерживает модели отложенной сборки на основе Sliver.

Отложенная сборка на основе Sliver

Что представляет собой модель отложенной сборки, основанная на Sliver?

Часто прокручиваемые компоненты могут иметь очень много подкомпонентов и занимать очень большую общую высоту; создавать их все сразу было бы очень дорого! С этой целью Flutter предлагает концепцию Sliver (что означает «срезы» на китайском языке).Если прокручиваемый компонент поддерживает модель Sliver, то прокрутка может разделить подкомпоненты на несколько «щепок» (Sliver), только когда Sliver появляется в строиться только тогда, когда он находится в окне просмотра, эта модель также известна как «модель отложенного строительства на основе Sliver».

Пример исходного кода

Конструктор выглядит следующим образом:

ListView({
	...  
	//可滚动组件的公共参数
	Axis scrollDirection = Axis.vertical,
	bool reverse = false,
	ScrollController controller,
	bool primary,
	ScrollPhysics physics,	
	EdgeInsetsGeometry padding,	
	
	//ListView各个构造函数的共同参数
	this.itemExtent,
	bool shrinkWrap = false,
	bool addAutomaticKeepAlives = true,
	bool addRepaintBoundaries = true,
	bool addSemanticIndexes = true,
	double cacheExtent,
	
	//子组件列表
	List<Widget> children = const <Widget>[],
	int semanticChildCount,
	DragStartBehavior dragStartBehavior = DragStartBehavior.start,
})

объяснение атрибута

scrollDirection

Определить направление качения дочерней сборки (расположенное направление), по умолчанию — вертикальное направление.

scrollDirection:Axis.horizontal,горизонтальное направление
scrollDirection:Axis.vertical,вертикальное направление

reverse

Определить направление прокрутки соответствует направлению для чтения

primary

значениеtrueилиfalse, я пробовал, вроде бесполезно, не знаю то ли я не так понял, то ли что, напишите сначала

controller

Это свойство получает одинScrollControllerобъект.ScrollController.
СвязанныйScrollControllerДля использования и подробностей, пожалуйста, обратитесь кЭлементы управления прокруткой Flutter -> Мониторинг и контроль прокрутки (ScrollController)

По умолчанию в дереве виджетов будет дефолтPrimaryScrollController, если прокручиваемый компонент в поддереве явно не указанcontroller,а такжеprimaryСтоимость свойстваtrueкогда (по умолчаниюtrue), прокручиваемый компонент будет использовать это значение по умолчанию.PrimaryScrollController. Преимущества такого механизмаРодительский компонент может управлять поведением прокрутки прокручиваемых компонентов в поддереве.,

physics

Это свойство принимает одинScrollPhysicsТип объектов, он определяет, как компоненты прокрутки реагируют на действия пользователя, например, когда пользователь проводит пальцем вверх, продолжает выполнять анимацию или перемещается к границе, как отображать.

shrinkWrap

Атрибут указывает, чтобы установить общую длину подсагмерыListViewfalse.
по умолчанию,ListView会在滚动方向尽可能多的占用空间。 когдаListViewshrinkWrapдолжно бытьtrue

itemExtent

Если этот параметр неnull, это заставитchildren"длина" этоitemExtentзначение;

itemExtentitemExtent

addAutomaticKeepAlives

Это свойство указывает, следует ли обернуть элемент списка (дочерний компонент) вAutomaticKeepAliveв компоненте;

В лениво загружаемом списке, если вы оберните элементы списка вAutomaticKeepAlive, элемент списка не будет переработан, когда он выскользнет из окна просмотра, он будет использоватьKeepAliveNotificationсохранить его состояние. Если элемент списка поддерживает свой собственныйKeepAliveстатус, то этот параметр должен быть установлен вfalse.

addRepaintBoundaries

Это свойство указывает, следует ли обернуть элемент списка (дочерний компонент) вRepaintBoundaryв компоненте.
Когда прокручиваемый компонент прокручивается, оберните элемент списка вRepaintBoundaryможно избежатьБесплатная перерисовка элемента списка, но не добавляет, когда накладные расходы из элемента списка RedRawing очень маленький (как блок цвета, или короткий текст)RepaintBoundaryНаоборот, это будет более эффективно. а такжеaddAutomaticKeepAliveНапример, если элемент списка поддерживает свой собственныйKeepAliveстатус, то этот параметр должен быть установлен вfalse.

addSemanticIndexes

Это свойство указывает, следует ли обернуть дочерний элемент управления вIndexedSemantics, используемый для обеспечения семантики доступности

cacheExtent

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

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

semanticChildCount

Такие как:ListViewбуду использоватьchildrenListView.separatedбуду использоватьchildrenПоловина длины

children

здесьchildren

здесьchildrenпараметры, он получит список,Но этот метод подходит для случая, когда имеется лишь небольшое количество подкомпонентов.. Потому что этот метод требует всехchildrenсоздаются раньше времени (что много работы), а не ждет, пока дочерний компонент на самом деле не отобразится, то есть.построен через конструктор по умолчаниюListViewМодель ленивой загрузки на основе Sliver не применяется..

Опять же, прокручиваемые компоненты проходятListкак егоchildrenПри использовании свойств это применимо только к случаям с несколькими подкомпонентами, что является общим правилом.

ListView.builder

надchildrenПодходит только для использования с меньшим объемом данных

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

Пример исходного кода

Конструктор выглядит следующим образом:

ListView.builder({
  // ListView公共参数已省略  
  ...
  @required IndexedWidgetBuilder itemBuilder,
  int itemCount,
  ...
})

объяснение атрибута

itemBuilder

Это строитель для элементов списка, типаIndexedWidgetBuilder, возвращаемое значение — это виджет (то есть компонент). Когда список прокручивается до определенногоindexКогда местоположение достигнуто, вызывается конструктор для создания элемента списка, который представляет собой так называемую модель ленивой загрузки на основе Sliver.

itemCount

Это свойство представляет количество элементов списка, если оноnull, это означает бесконечный список

ListView.builder(
	itemCount: 100,
	itemExtent: 50.0, //强制高度为50.0,如果这个值越来越小的话,那么显示的值是会重叠的
	itemBuilder: (BuildContext context, int index) {
	  return ListTile(title: Text("$index"));
})

текущий результат:

ListView.separated

ListView.separatedКомпонент разделения может быть добавлен между сгенерированными элементами списка.

это лучше, чемListView.builderодин дополнительныйseparatorBuilderпараметр, который является генератором разделенных компонентов.

Пример кода:

Добавьте синее подчеркивание к нечетным строкам и красное подчеркивание к четным строкам.

import 'package:flutter/material.dart';

class CategoryPage extends StatefulWidget {
  @override
  _CategoryPageState createState() => _CategoryPageState();
}

class _CategoryPageState extends State<CategoryPage> {
  @override
  Widget build(BuildContext context) {
    //下划线widget预定义以供复用。
    Widget Lineblue = Divider(color: Colors.blue);
    Widget Linered = Divider(color: Colors.red);
    return Scaffold(
        appBar: AppBar(
          title: Text(
            "ListView.separated",
            // style: TextStyle(color: Color(0xFF1E88E5)),
          ),
        ),
        body: ListView.separated(
          itemCount: 100,
          //列表项构造器
          itemBuilder: (BuildContext context, int index) {
            return ListTile(title: Text("$index"));
          },
          //分割器构造器
          separatorBuilder: (BuildContext context, int index) {
            return index % 2 == 0 ? Lineblue : Linered;
          },
        ));
  }
}

текущий результат:

ListViewэкспонат.

Здесь нам нужно установить пакетenglish_words: ^3.1.5(существуетpubspec.yamlв файлеdependencies

Пример кода:

import 'package:flutter/material.dart';
import 'package:english_words/english_words.dart';

class CategoryPage extends StatefulWidget {
  @override
  _CategoryPageState createState() => _CategoryPageState();
}

class _CategoryPageState extends State<CategoryPage> {
  static const loadingTag = "##loading##"; //表尾标记
  var _words = <String>[loadingTag];

  @override
  void initState() {
    super.initState();
    _retrieveData();
  }

  @override
  Widget build(BuildContext context) {
    return ListView.separated(
      itemCount: _words.length,
      itemBuilder: (context, index) {
        //如果到了表尾
        if (_words[index] == loadingTag) {
          //不足100条,继续获取数据
          if (_words.length - 1 < 100) {
            //获取数据
            _retrieveData();
            //加载时显示loading
            return Container(
              padding: const EdgeInsets.all(16.0),
              alignment: Alignment.center,
              child: SizedBox(
                  width: 24.0,
                  height: 24.0,
                  child: CircularProgressIndicator(strokeWidth: 2.0)),
            );
          } else {
            //已经加载了100条数据,不再获取数据。
            return Container(
                alignment: Alignment.center,
                padding: EdgeInsets.all(16.0),
                child: Text(
                  "没有更多了",
                  style: TextStyle(color: Colors.grey),
                ));
          }
        }
        //显示单词列表项
        return ListTile(title: Text(_words[index]));
      },
      separatorBuilder: (context, index) => Divider(height: .0),
    );
  }

  void _retrieveData() {
    Future.delayed(Duration(seconds: 2)).then((e) {
      _words.insertAll(
          _words.length - 1,
          //每次生成20个单词
          generateWordPairs().take(20).map((e) => e.asPascalCase).toList());
      setState(() {
        //重新构建列表
      });
    });
  }
}

_retrieveData()Функция состоит в том, чтобы имитировать асинхронную выборку данных из источника данных,
english_wordsупаковкаgenerateWordPairs()Метод может генерировать 20 слов за раз.

текущий результат:

ListTile

Здесь мы говоримListTile.
ListTileОбычно используется для заполнения в трепетанииListView.

Пример исходного кода:

Конструктор выглядит следующим образом:

const ListTile({
	Key key,
	this.leading,
	this.title,
	this.subtitle,
	this.trailing,
	this.isThreeLine = false,
	this.dense,
	this.contentPadding,
	this.enabled = true,
	this.onTap,
	this.onLongPress,
	this.selected = false,
})

объяснение атрибута

title

titleПараметр может принимать любой виджет, но обычно это текстовый виджет.

Пример кода:

ListTile(
  title: Text('我喜欢你!'),
)

subtitle

Он отображается субтитром меньший текст в заголовке (заголовок) ниже

Пример кода:

ListTile(
  title: Text('我喜欢你!'),
  subtitle: Text('你喜欢我吗?'),
)

dense

Уменьшите текст и соберите все вместе

Пример кода:

ListTile(
  title: Text('我喜欢你!'),
  subtitle: Text('你喜欢我吗?'),
  dense:true,
)

leading

Добавьте изображение или значок в начало списка.

Пример кода:

ListTile(
  leading: CircleAvatar(
    backgroundImage: NetworkImage(imageUrl),
  ),
  title: Text('我喜欢你'),
  subtitle: Text('你喜欢我吗?'),
  dense:true,
)

trailing

Поместите изображение в конец списка.

Пример кода:

ListTile(
  leading: CircleAvatar(
    backgroundImage: NetworkImage(imageUrl),
  ),
  title: Text('我喜欢你'),
  subtitle: Text('你喜欢我吗?'),
  dense:true,
  trailing: Icon(Icons.keyboard_arrow_right),
)

contentPadding

Установите содержимое полей, по умолчанию 16
Я поставил 30 здесь

Пример кода:

ListTile(
  leading: CircleAvatar(
    backgroundImage: NetworkImage(imageUrl),
  ),
  title: Text('我喜欢你'),
  subtitle: Text('你喜欢我吗?'),
  dense:true,
  trailing: Icon(Icons.keyboard_arrow_right),
  contentPadding: EdgeInsets.symmetric(horizontal: 30.0),
)

selected

Если список выбранitemпункт, то цвет текста и значков будет основным цветом темы.

Пример кода:

ListTile(
  leading: CircleAvatar(
    backgroundImage: NetworkImage(imageUrl),
  ),
  title: Text('我喜欢你'),
  subtitle: Text('你喜欢我吗?'),
  dense:true,
  trailing: Icon(Icons.keyboard_arrow_right),
  contentPadding: EdgeInsets.symmetric(horizontal: 30.0),
  selected: true,
)

onTap, onLongPress

onTapнажать,onLongPressПри длительном нажатии.

Пример кода:

ListTile(
  leading: CircleAvatar(
    backgroundImage: NetworkImage(imageUrl),
  ),
  title: Text('我喜欢你'),
  subtitle: Text('你喜欢我吗?'),
  dense:true,
  trailing: Icon(Icons.keyboard_arrow_right),
  contentPadding: EdgeInsets.symmetric(horizontal: 30.0),
  selected: true,
  onTap: () {
    // do something
  },
  onLongPress: (){
    // do something else
  },
)

enabled

КenableУстановить какfalse

import 'package:flutter/material.dart';
import 'package:english_words/english_words.dart';

class CategoryPage extends StatefulWidget {
  @override
  _CategoryPageState createState() => _CategoryPageState();
}

class _CategoryPageState extends State<CategoryPage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('ListTile'),),
        body: Column(
      children: <Widget>[
        ListTile(
          leading: CircleAvatar(
            backgroundImage: AssetImage('images/Test.jpg'),
          ),
          title: Text('我喜欢你'),
          subtitle: Text('你喜欢我吗?'),
          dense: true,
          trailing: Icon(Icons.keyboard_arrow_right),
          contentPadding: EdgeInsets.symmetric(horizontal: 30.0),
          // selected: true,
          onTap: () {
            // do something
          },
          onLongPress: () {
            // do something else
          },
        ),
        ListTile(
          leading: CircleAvatar(
            backgroundImage: AssetImage('images/Test.jpg'),
          ),
          title: Text('我喜欢你'),
          subtitle: Text('你喜欢我吗?'),
          dense: true,
          trailing: Icon(Icons.keyboard_arrow_right),
          contentPadding: EdgeInsets.symmetric(horizontal: 30.0),
          selected: true,
          onTap: () {
            // do something
          },
          onLongPress: () {
            // do something else
          },
        )
      ],
    ));
  }
}

текущий результат:

Добавить фиксированный заголовок списка

Много раз нам нужно добавить в список фиксированный заголовок.

Нам нужно получитьListViewАвтоматически растягивать по размеру экрана, на этот раз нам нужно использовать эластичную компоновку.Flex, если вы не знаете, пожалуйста, переместитеЭлементы управления Flutter Layout -> Flex, расширенный

мы можем использоватьExpandedАвтоматически растягиваться размер компонента, и мы также сказалиColumnЭто унаследовано отFlex, Таким образом, мы можем напрямую использоватьColumn+Expandedреализовать,

Пример кода:

Column(children: <Widget>[
  ListTile(title: Text("数字列表")),
  Expanded(
	child: ListView.builder(itemBuilder: (BuildContext context, int index) {
	  return ListTile(title: Text("$index"));
	}),
  ),
]);

текущий результат:


T_T