Всё о Slivers и немного больше. Часть 1

Всем привет! На связи Арсен, Flutter-разработчик Mad Brains. Многие из вас наверняка уже знакомы с Slivers, ведь это мощный инструмент для создания динамичных и адаптивных прокручиваемых областей в приложениях Flutter. В этом цикле статей рассмотрим все существующие sliver-виджеты во Flutter, чтобы познакомиться с каждым из них, понять, какие задачи они решают, и как их можно применять. Мы не будем углубляться в детали, дабы не усложнять материал, а обозначим основные особенности и отличия каждого сливера, чтобы понимать, какие вообще существуют и в нужный момент воспользоваться ими. Итак, погнали!

Тест на Flutter-разработчика: думскролинг или sliver?

Тест на Flutter-разработчика: думскролинг или sliver?

Для начала немного общей информации о скролле.

ScrollView — виджет, который объединяет Scrollable и Viewport для создания интерактивной области прокрутки содержимого.
Scrollable — виджет, который с помощью распознавания жестов, управляет прокруткой и информирует Viewport.
Viewport — виджет, с помощью которого можно просматривать часть более крупного содержимого. Дочерние объекты для Viewport — Slivers.
Эта компания находиться под капотом у всех прокручиваемых виджетов, в том числе и у классического ListView. Рассмотрим все виды сливеров, а начнем как раз со списков.

SliverList

Пример работы SliverList.

Пример работы SliverList.

SliverList — размещает множество элементов в линейном массиве вдоль главной оси, то есть отображает список элементов.

SliverList(
    delegate: SliverChildListDelegate(items),
),

Несколько сливеров, которые делают тоже самое, что и SliverList, но с нюансом:

SliverFixedExtentList — отличается тем, что размер дочерних элементов по главной оси равен заданному значению.

SliverFixedExtentList(
  itemExtent: 100.0,
  delegate: SliverChildListDelegate(items),
),

SliverPrototypeExtentList — тут размер по главной оси уже задается виджетом-прототипом, удобно, когда высота элементов может меняться в зависимости от контента, но при этом остается одинаковой для всех элементов.

SliverPrototypeExtentList(
  prototypeItem: someWidget,
  delegate: SliverChildListDelegate(items),
),

SliverVariedExtentList —, а тут размер определяется по правилу, возвращаемому полем itemExtentBuilder. Сливер более эффективен, чем SliverList, потому что не нужно размещать дочерние элементы, чтобы получить их протяженность вдоль главной оси и более гибкий, чем SliverFixedExtentList (или SliverPrototypeExtentList), потому что позволяет дочерним элементам иметь разные размеры. SliverLayoutDimensions — объект, предоставляющий информацию о текущих размерах видимой области, в которой находится SliverVariedExtentList.

SliverVariedExtentList(
  itemExtentBuilder: (int index, SliverLayoutDimensions dimensions) {
    return (index + 1) * 3 + 40;
  },
  delegate: SliverChildListDelegate(items),
),

SliverReorderableList

Пример работы SliverReorderableList 

Пример работы SliverReorderableList 

SliverReorderableList — список, который позволяет пользователю интерактивно изменять порядок элементов, обычный ReorderableList использует именно этот сливер под капотом.

SliverReorderableList(
  itemBuilder: (context, index) {
    return ListTile(items[index]);
  },
  itemCount: items.length,
  onReorder: (oldIndex, newIndex) {
    setState(() {
      if (newIndex > oldIndex) {
        newIndex -= 1;
      }
      final item = items.removeAt(oldIndex);
      items.insert(newIndex, item);
    });
  },
),

SliverAnimatedList

Пример работы SliverAnimatedList

Пример работы SliverAnimatedList

SliverAnimatedList — SliverList, который анимирует элементы при их вставке или удалении. Для вставки или удаления элементов используется SliverAnimatedListState, чтобы к нему обратиться, либо укажите GlobalKey,  либо используйте статический метод SliverAnimatedList.of.

final GlobalKey _listKey = GlobalKey();
...
SliverAnimatedList(
  key: _listKey,
  initialItemCount: items.length,
  itemBuilder: (context, index, animation) {
    return ListTile(items[index], animation);
  },
),

SliverFillViewport

Пример работы SliverFillViewport

Пример работы SliverFillViewport

SliverFillViewport — немного выбивается от предыдущих сливеров, нет в названии слова List, однако в остальном очень похож, также получает делегат, предоставляющий дочерние элементы. Главная особенность — делает каждый элемент заполняющим область просмотра, степень заполнения можно регулировать параметром viewportFraction. 

SliverFillViewport(
  delegate: SliverChildListDelegate(items),
),

SliverGrid

Пример работы SliverGrid

Пример работы SliverGrid

SliverGrid — размещает дочерние элементы в двумерной компоновке. GridView реализован с помощью этого сливера.

SliverGrid(
  gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
    crossAxisCount: 2,
  ),
  delegate: SliverChildListDelegate(items),
),

SliverAnimatedGrid

Пример работы SliverAnimatedGrid

Пример работы SliverAnimatedGrid

SliverAnimatedGrid — SliverGrid, который анимирует элементы при их вставке или удалении. Тут также, как и в случае SliverAnimatedList, для вставки и удаления используем SliverAnimatedGridState (через GlobalKey или SliverAnimatedGrid.of).

final GlobalKey _gridKey = GlobalKey();
...
SliverAnimatedGrid(
  key: _gridKey,
  initialItemCount: items.length,
  gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
    crossAxisCount: 2,
  ),
  itemBuilder: (context, index, animation) {
    return GridTile(items[index], animation);
  },
),

На этом всё, в следующей статье продолжим тему списков и поговорим об их делегатах. Пишите в комментариях, какими sliver-виджетами из перечисленных пользуетесь.

© Habrahabr.ru