【FlutterUnit周边】SliverPersistentHeader使用指南

零、前言

如果你进入过FlutterUnit,那么主页中头部的Tap栏你应该印象深刻。 如下效果: 在上滑时Tap栏会逐渐变矮,直到最小值。下拉到顶时变矮的Tap栏会逐渐变高,直到最大值 FlutterUnit本身主页比较复杂,本文就来写一个最简实践,用最少的代码来实现这个效果。 本文的主人公是SliverPersistentHeader,来一起看一下它的用法。

| 上滑效果 | 下拉效果 | | ---- | ---- | | 滑动效果 |下拉效果 |

一、项目初始
1. 程序入口

在 main 函数中使用SystemChrome.setSystemUIOverlayStyle让状态栏变透明 测试 demo 的核心组件在 SliverPersistentHeaderDemo

```Dart void main() { //设置透明 状态栏 SystemUiOverlayStyle style = SystemUiOverlayStyle(statusBarColor: Colors.transparent); SystemChrome.setSystemUIOverlayStyle(style); runApp(MyApp()); }

class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', debugShowCheckedModeBanner: false, theme: ThemeData( primarySwatch: Colors.blue ), home: Scaffold( body: SliverPersistentHeaderDemo(), )); } } ```


2.构建色彩列表

我们要构建的是比较复杂的滑动效果, 可以使用CustomScrollView,其中slivers接收Sliver家族组件的列表。CustomScrollView不是本文的主人公,这里不多说,以后会有专篇。 如下: _buildSliverList负责构建SliverList,其中颜色的item组件的构建交由_buildColorItem。我建议大家可以把构建的粒度细分一下,不要什么都塞一块,这样看起来会比较清晰。

| 色彩列表 | 色彩列表 | | ------------------------------------------------------------ | ------------------------------------------------------------ | | image-20201025093338154 | image-20201025093440791 |

```dart class SliverPersistentHeaderDemo extends StatelessWidget { // 色彩数据 final List data = List.generate(24, (i) => Color(0xFFFF00FF - 24*i));

@override Widget build(BuildContext context) { return CustomScrollView( slivers: [ // TODO 添加 bar _buildSliverList() ], ); }

// 构建颜色列表 Widget buildSliverList() => SliverList( delegate: SliverChildBuilderDelegate( (, int index) => _buildColorItem(data[index]), childCount: data.length), );

// 构建颜色列表item

Widget _buildColorItem(Color color) => Card( child: Container( alignment: Alignment.center, width: 100, height: 60, color: color, child: Text( colorString(color), style: const TextStyle( color: Colors.white, shadows: [ Shadow(color: Colors.black, offset: Offset(.5, .5), blurRadius: 2) ]), ), ), );

// 颜色转换为文字

String colorString(Color color) => "#${color.value.toRadixString(16).padLeft(8, '0').toUpperCase()}"; } ```

这样初始的demo就搭建好了,下面来看看SliverPersistentHeader的用法吧


二、认识 SliverPersistentHeader
1.SliverPersistentHeader属性一览

| 属性名 | 类型 | 默认值 | 介绍 | | -------- | ------------------------------ | -------- | ------------ | | delegate | SliverPersistentHeaderDelegate | required | 组件构建代理 | | pinned | bool | false | 是否固定 | | floating | bool | false | 是否浮动 |


2.SliverPersistentHeaderDelegate的使用

估计很多人看到XXXDelegate就有种劝退的感觉。先别怕,看看它是什么。 可以看到它是抽象类,说明需要实现一些抽象方法,而一般抽象方法都会为我们回调一些有价值的东西 查看他的族谱,发现没有可以使用的子类,那么想使用它,二话不说,先写个他的子类。

image-20201025094150594

现在写一个UnitPersistentHeaderDelegate实现一下SliverPersistentHeaderDelegate, 可以看到有下面四个需要实现的方法: build,maxExtent,minExtent,shouldRebuild

```dart class UnitPersistentHeaderDelegate extends SliverPersistentHeaderDelegate { @override Widget build( BuildContext context, double shrinkOffset, bool overlapsContent) { print( "=====shrinkOffset:$shrinkOffset======overlapsContent:$overlapsContent===="); final String info = 'shrinkOffset:${shrinkOffset.toStringAsFixed(1)}' '\noverlapsContent:$overlapsContent'; return Container( alignment: Alignment.center, color: Colors.orangeAccent, child: Text( info, style: TextStyle(fontSize: 20, color: Colors.white), ), ); } @override double get maxExtent => 120;

@override double get minExtent => 80;

@override bool shouldRebuild(covariant SliverPersistentHeaderDelegate oldDelegate) => false; } ```

先简单实现一下使用上面定义的UnitPersistentHeaderDelegate查看效果: 可以看到上面的build方法的作用就是构建组件,shrinkOffset为偏移量 头部栏组件开始完全展开maxExtent高度,随着列表上滑而上滑,可以从日志里看出最大上滑高度为maxExtent,这是默认pinned=false,floating=false的滑动效果。

| 上滑测试 | 下拉测试 | | ------------------------------------------------------------ | ------------------------------------------------------------ | | Delegate上滑测试 | Delegate下拉测试 |

```dart //英雄所见... return CustomScrollView( slivers: [ _buildPersistentHeader(), //<-- 在列表上方创建PersistentHeader _buildSliverList() ], ); }

// 使用UnitPersistentHeaderDelegate创建PersistentHeader Widget _buildPersistentHeader() => SliverPersistentHeader( delegate: UnitPersistentHeaderDelegate());

```


3.SliverPersistentHeader的pinned与floating属性

下面开始试验:

| pinnedtruefloatingfalse | pinnedtruefloatingtrue | | ------------------------------------------------------------ | ------------------------------------------------------------ | | pinned<em>true</em>floating<em>false | pinned</em>true<em>floating</em>true | | 上滑:顶部会留出minExtent的高度,不再随上滑而减小 | 上滑:顶部会留出minExtent的高度,不再随上滑而减小 | | 下拉:直到滑到顶端时,剩余空间才会展开 | 下拉: 任意位置下拉时, 剩余空间会展开 |


下面开始试验:

| pinnedfalsefloatingfalse | pinnedfalsefloatingtrue | | ------------------------------------------------------------ | ------------------------------------------------------------ | | pinned<em>false</em>floating<em>false | pinned</em>false<em>floating</em>true_ | | 上滑: 顶部会滑出 | 上滑:顶部会滑出 | | 下拉:直到滑到顶端时,顶部才会展开 | 下拉: 任意位置下拉时, 空间会展开 |


三、使用 SliverPersistentHeader
1. 封装PersistentHeaderBuilder

上面使用起来比较麻烦,可以自定义一个PersistentHeaderBuilder来简化构建

使用builder属性,将创建的逻辑移交到使用时,可以回调一些有价值的数据,比如偏移量

```dart class PersistentHeaderBuilder extends SliverPersistentHeaderDelegate { final double max; final double min; final Widget Function(BuildContext context, double offset) builder;

PersistentHeaderBuilder( {this.max = 120, this.min = 80, @required this.builder}) : assert(max >= min && builder != null);

@override Widget build( BuildContext context, double shrinkOffset, bool overlapsContent) { return builder(context, shrinkOffset); }

@override double get maxExtent => max;

@override double get minExtent => min;

@override bool shouldRebuild(covariant PersistentHeaderBuilder oldDelegate) => max != oldDelegate.max || min != oldDelegate.min || builder != oldDelegate.builder; } ```


2.使用PersistentHeaderBuilder

dart Widget _buildPersistentHeader() => SliverPersistentHeader( pinned: true, floating: false, delegate: PersistentHeaderBuilder(builder: (ctx, offset) => Container( alignment: Alignment.center, color: Colors.orangeAccent, child: Text( "shrinkOffset:${offset.toStringAsFixed(1)}", style: TextStyle(fontSize: 20, color: Colors.white), ), )));


3.多个SliverPersistentHeader的使用

你也可以根据offset来进行一些变换处理。 多个SliverPersistentHeader是可以共存的,如下

| 上滑 | 下拉 | | ------------------------------------------------------------ | ------------------------------------------------------------ | | two<em>bar | tow</em>bar_2 |

dart Widget _buildPersistentHeader2() => SliverPersistentHeader( pinned: false, floating: false, delegate: PersistentHeaderBuilder( max: 100, builder: (ctx, offset) => Container( transform: Matrix4.rotationZ(offset / 120 * pi / 2), alignment: Alignment.center, color: Colors.blue, child: Text( "shrinkOffset:${offset.toStringAsFixed(1)}", style: TextStyle(fontSize: 20, color: Colors.white), ), )));

SliverPersistentHeader基本用法就是这样,你可以基于此实现很多有意思的滑动效果 最后欢迎关注我的开源项目 FlutterUnit,FlutterUnit相关的周边文章会陆续更新,其中包括一些Flutter组件的用法,或一些FlutterUnit实现的细节,FlutterUnit的重大更新等,欢迎持续关注。

@张风捷特烈 2020.10.25 未允禁转 ~ END ~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值