Всем привет! Продолжаем разбор сливеров, в предыдущих частях серии мы рассмотрели сливеры-списки, сливеры, которые помогают управлять компоновкой и распределением пространства. В этой же статье посмотрим на сливеры, которые дают возможности для более гибкого управления размерами и поведением элементов во время прокрутки. В частности посмотрим, что сливеры умеют делать с заголовком.
Предыдущие материалы по теме:
Такие разные Slivers. Часть 1: обзор и применение во Flutter
Такие разные Slivers. Часть 2: базовые классы и делегаты
Такие разные Slivers. Часть 3: работа с пространством

SliverLayoutBuilder — аналог обычного LayoutBuilder, создает sliver, который может зависеть от его собственных SliverConstraints, то есть от ограничений размера родительского виджета.
SliverLayoutBuilder(builder: (context, constraints) {
return SliverFixedExtentList(
itemExtent: constraints.viewportMainAxisExtent / 5,
delegate: SliverChildListDelegate(items),
);
}
)

PinnedHeaderSliver — закрепляет свой дочерний виджет в верхней части CustomScrollView.
CustomScrollView(
slivers: <Widget>[
PinnedHeaderSliver(
child: SomeWidget(),
),
SomeSliver(),
],
),

SliverResizingHeader — также закрепляет свой дочерний виджет сверху, но изменяет свой размер при прокрутке, основываясь на прототипах минимального и максимального размера.
CustomScrollView(
slivers: <Widget>[
SliverResizingHeader(
minExtentPrototype: AnotherPrototypeWidget(),
maxExtentPrototype: SomePrototypeWidget(),
child: SomeWidget(),
),
SomeSliver(),
],
),

SliverFloatingHeader — закрепляется сверху, но скрывает дочерний виджет, когда пользователь прокручивает вперед, и показывает, когда пользователь прокручивает назад.
Можно настроить стиль анимации появления/скрытия с помощью параметра [animationStyle].
Во время прокрутки заголовок и остальной контент перемещаются синхронно. Параметр [snapMode] задает, будет ли заголовок, прежде чем полностью появится, накладываться на остальное содержимое (FloatingHeaderSnapMode.overlay) или по мере расширения заголовка, остальное содержимое будет продолжать прокручиваться (FloatingHeaderSnapMode.scroll).
CustomScrollView(
slivers: <Widget>[
SliverFloatingHeader(
snapMode: FloatingHeaderSnapMode.overlay,
child: SomeWidget(),
),
SomeSliver(),
],
),

SliverPersistentHeader — сливер, размер которого меняется при прокрутке. Используется, если нужно создать свой собственный пользовательский заголовок с эффектом уменьшения/увеличения во время скролла, например, SliverAppBar под капотом использует именно его.
Для настройки используется делегат SliverPersistentHeaderDelegate.
Параметр [pinned] отвечает за закрепление в начале при достижении минимального размера.
Параметр [floating] отвечает за мгновенное увеличение размера хедера при скролле наверх.
CustomScrollView(
slivers: <Widget>[
SliverPersistentHeader(
pinned: true,
floating: false,
delegate: HeaderDelegate(
child: SomeWidget(),
),
),
SomeSliver(),
],
),
...
class HeaderDelegate extends SliverPersistentHeaderDelegate {
const HeaderDelegate({required this.child});
final Widget child;
@override
double get minExtent => 50;
@override
double get maxExtent => 200;
@override
Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) {
return SizedBox.expand(child: child);
}
@override
bool shouldRebuild(HeaderDelegate oldDelegate) => false;
}

TreeSliver — это сливер для отображения древовидных структур данных с возможностью сворачивания и разворачивания ветвей. Принимает массив TreeSliverNode, которые представляют параметры дочерних элементов.
TreeSliver<String>(
tree: [
TreeSliverNode(
'Root 1',
children: [
TreeSliverNode('Child 1.1'),
TreeSliverNode('Child 1.2'),
],
),
TreeSliverNode(
'Root 2',
children: [
TreeSliverNode('Child 2.1'),
TreeSliverNode('Child 2.2'),
],
),
],
treeNodeBuilder: (BuildContext context, TreeSliverNode<Object?> node, AnimationStyle animationStyle) {
return TreeSliver.defaultTreeNodeBuilder(
context,
node,
animationStyle,
);
},
),

SliverOverlapAbsorber — захватывает перекрытую область в прокручиваемых компонентах, в основном в NestedScrollView (прокручиваемый виджет, внутри которого могут быть вложены другие прокручиваемые виджеты). SliverOverlapAbsorber работает в связке с SliverOverlapAbsorberHandle, который сохраняет данные о перекрытии, и SliverOverlapInjector, который возвращает это пространство обратно в компоновку, чтобы остальные сливеры могли корректно использовать его.В примере, без SliverOverlapInjector, SomeSliver заезжал бы под SliverAppBar, а в данном случае SliverOverlapInjector дает отступ, равный размеру SliverAppBar (хранится в SliverOverlapAbsorberHandle).
NestedScrollView(
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
return <Widget>[
SliverOverlapAbsorber(
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
sliver: SliverAppBar(
title: const Text('NestedScroll'),
pinned: true,
),
),
];
},
body: Builder(
builder: (context) {
return CustomScrollView(
slivers: <Widget>[
SliverOverlapInjector(
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
),
SomeSliver(),
],
);
}
),
)
Это была предпоследняя часть серии, в заключительной статье рассмотрим аналоги обычных (box-based) виджетов в мире сливеров.