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

Предыдущие материалы по теме:
Такие разные 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) виджетов в мире сливеров.

Комментарии (0)