likes
comments
collection
share

Flutter 组件更新 | Slivers 体系 5 位新成员 @v3.13

作者站长头像
站长
· 阅读数 21

1. 介绍一下 5 个新的 Sliver 组件

在 Flutter 3.13 更新中,增加了 5 位新的 Sliver 相关组件,用于滑动视口中,完成特定功能。这篇文章将介绍一下它们的作用和使用场景。

组件名中文名介绍
SliverMainAxisGroup主轴分组滑片可以容纳多个 Sliver 组件,在主轴方向上分组
DecoratedSliver装饰滑片对 Sliver 进行装饰
SliverConstrainedCrossAxis交叉轴约束滑片交叉轴方向上固定某个 Sliver的尺寸
SliverCrossAxisExpanded交叉轴延展滑片交叉轴方向上设置某个 Sliver的尺寸占比
SliverCrossAxisGroup交叉轴分组滑片可以容纳多个 Sliver 组件,在交叉轴方向上分组

这五个组件的使用案例,将在后续加入到开源项目 FlutterUnit 中,欢迎大家对项目的关注和支持 ~


2. 主轴滑片分组: SliverMainAxisGroup 组件

具体使用场景是: 比如下面是 QQ 中分组列表滑动效果,组名下有若干成员,组的标题在滑动中会进行吸附,而且在滑动到下一组标题时,上一标题会被滑出;同样,下滑时展现也是如此。

上滑效果下滑效果
Flutter 组件更新 |  Slivers 体系 5 位新成员 @v3.13Flutter 组件更新 |  Slivers 体系 5 位新成员 @v3.13

下面,我们将基于 SliverMainAxisGroup 组件实现下面效果:

上滑效果下滑效果
Flutter 组件更新 |  Slivers 体系 5 位新成员 @v3.13Flutter 组件更新 |  Slivers 体系 5 位新成员 @v3.13

首先准备一下数据,作为界面的填充内容:

class ItemData {
  final String groupName;
  final List<String> users;

  ItemData({required this.groupName, this.users = const []});

  static List<ItemData> get testData => [
        ItemData(groupName: '幻将术士', users: ['梦小梦', '梦千']),
        ItemData(
            groupName: '幻将剑客', users: ['捷特', '龙少', '莫向阳', '何解连', '浪封', '梦飞烟']),
        ItemData(groupName: '幻将弓者', users: ['巫缨', '巫妻孋', '摄王', '裔王', '梦童']),
        ItemData(
            groupName: '其他', users: List.generate(20, (index) => '小兵$index')),
      ];
}

然后在组件中通过数据,映射出 SliverMainAxisGroup 列表,每个 SliverMainAxisGroup 列表中可以容纳若干个 Sliver 滑块,只要让标题通过 SliverPersistentHeader 吸顶即可:

class MyHomePage extends StatelessWidget{
  const MyHomePage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('SliverMainAxisGroup')),
      body: CustomScrollView(
        slivers: ItemData.testData.map(_buildGroup).toList(),
      ),
    );
  }

  Widget _buildGroup(ItemData itemData) {
    return SliverMainAxisGroup(slivers: [
      SliverPersistentHeader(
        pinned: true,
        delegate: HeaderDelegate(itemData.groupName),
      ),
      SliverList(
        delegate: SliverChildBuilderDelegate(
          (_, index) => _buildItemByUser(itemData.users[index]),
          childCount: itemData.users.length,
        ),
      ),
    ]);
  }

  Widget _buildItemByUser(String user) {
    return Container(
      alignment: Alignment.center,
      height: 56,
      child: Row(
        children: [
          Padding(
            padding: const EdgeInsets.only(left: 20, right: 10.0),
            child: FlutterLogo(size: 30),
          ),
          Text(
            user,
            style: const TextStyle(fontSize: 16),
          ),
        ],
      ),
    );
  }
}

下面是吸顶标题的代理类,这样一共不到百行代码,就实现了分组滑动的效果,可以说是很方便的。

class HeaderDelegate extends SliverPersistentHeaderDelegate {
  const HeaderDelegate(this.title);

  final String title;

  @override
  Widget build(
      BuildContext context, double shrinkOffset, bool overlapsContent) {
    return Container(
        alignment: Alignment.centerLeft,
        color: const Color(0xffF6F6F6),
        padding: const EdgeInsets.only(left: 20),
        height: 40,
        child: Text(title));
  }

  @override
  double get maxExtent => minExtent;

  @override
  double get minExtent => 40;

  @override
  bool shouldRebuild(covariant HeaderDelegate oldDelegate) => title!=oldDelegate.title;
}

3. 交叉轴分组相关 Sliver 组件

其中 SliverConstrainedCrossAxisSliverCrossAxisExpanded 用于控制滑片在交叉轴的尺寸;有人可能会疑惑,一般来说,交叉轴方向的尺寸不就是视口尺寸吗,为什么需要控制交叉轴方向的滑片尺寸呢?有些场景下,我们期望交叉轴方向可以排若干个 Sliver 滑块,共同响应滚动,特别是像宽度充裕的桌面端。

如下所示,左中右三块 SliverList 水平排布,共同滑动。这种场景在之前是很难实现的,现在有了 SliverCrossAxisGroup 组件,就可以在竖直滑动视口中,将若干个 Sliver 水平排列,作为一个滑片组。而 SliverConstrainedCrossAxisSliverCrossAxisExpanded 两个组件就是用于控制滑片在交叉轴方向尺寸的,所以说这三位是同一条船上的。

下滑上滑
Flutter 组件更新 |  Slivers 体系 5 位新成员 @v3.13Flutter 组件更新 |  Slivers 体系 5 位新成员 @v3.13

SliverConstrainedCrossAxis 组件可以在交叉轴方向容纳若干个 Sliver 组件。比如竖直方向滑动中,他就类似于 Row 组件,将 Sliver 孩子们水平排列。其中:

SliverConstrainedCrossAxis:指定滑片的交叉轴尺寸。 SliverCrossAxisExpanded:指定滑片的交叉轴上占据的份额。

案例中需要准备三个 SliverList 的滑块,为了简单起见,这里简单封装一个 SliverColorList 用于构建滑块组件,可指定色块颜色、条目高、条目数量等:

class SliverColorList extends StatelessWidget {
  final double height;
  final double fontSize;
  final Color? color1;
  final Color? color2;
  final int count;
  const SliverColorList(
      {super.key,
      required this.height,
      required this.fontSize,
      required this.count,
      this.color1,
      this.color2});

  @override
  Widget build(BuildContext context) {
    return SliverList.builder(
      itemBuilder: (BuildContext context, int index) {
        return Container(
          color: index.isEven ? color1 : color2,
          height: height,
          child: Center(
            child: Text(
              'Item ${index}',
              style: TextStyle(fontSize: fontSize),
            ),
          ),
        );
      },
      itemCount: count,
    );
  }
}

下面就是 SliverCrossAxisGroup 的使用方式,其实很简单,塞入 slivers 列表就行了。其中通过 SliverConstrainedCrossAxis 可以指定某个滑块在水平方向的固定尺寸;也可以通过 SliverCrossAxisExpanded 指定在水平方向尺寸的占份,下面 tag1 和 tag2 处通过 flex 属性指定份额 1:2, 所以右侧滑块的水平尺寸是中间的两倍:

class SliverCrossAxisGroupExample extends StatelessWidget {
  const SliverCrossAxisGroupExample({super.key});

  @override
  Widget build(BuildContext context) {
    return CustomScrollView(
      slivers: <Widget>[
        SliverCrossAxisGroup(
          slivers: <Widget>[
            SliverConstrainedCrossAxis(
              maxExtent: 100,
              sliver: SliverColorList(
                height: 100.0,
                fontSize: 24,
                count: 8,
                color1: Colors.amber[300],
                color2: Colors.blue[300],
              ),
            ),
            SliverCrossAxisExpanded(
              flex: 1, // tag1
              sliver: SliverColorList(
                height: 80.0,
                fontSize: 18,
                count: 15,
                color1: Colors.green[300],
                color2: Colors.red[300],
              ),
            ),
            SliverCrossAxisExpanded(
                flex: 2, // tag2
                sliver: SliverColorList(
                  height: 50.0,
                  fontSize: 20,
                  count: 6,
                  color1: Colors.purple[300],
                  color2: Colors.orange[300],
                )),
          ],
        ),
      ],
    );
  }
}

这就是 SliverCrossAxisGroup、SliverConstrainedCrossAxis、SliverCrossAxisExpanded 三个组件的所有用法,还是非常简单和直观的。解决的场景是:

在交叉轴方向,需要摆放若干个滑块时,这些滑块可以共同滚动。


4. 装饰滑块 DecoratedSliver

DecoratedSliver 其实很好理解,它就是滑动版的 DecoratedBox, 可以在滑动视口中,用于装饰 Sliver 滑片。之前需要对滑片进行装饰,是很难做到的,因为滑块在布局上受到的是滑动约束 SliverConstraints ,而不是盒约束 BoxConstraints。现在有了 DecoratedSliver 组件,指定 decoration 装饰对象即可:

Flutter 组件更新 |  Slivers 体系 5 位新成员 @v3.13

标题
Flutter 组件更新 |  Slivers 体系 5 位新成员 @v3.13Flutter 组件更新 |  Slivers 体系 5 位新成员 @v3.13
SliverPadding(
  padding: EdgeInsets.symmetric(horizontal: 8, vertical: 8),
  sliver: DecoratedSliver(
    decoration: BoxDecoration(
      borderRadius: BorderRadius.circular(20),
      boxShadow: [
        BoxShadow(
            color: Color(0xFF111133),
            blurRadius: 2,
            offset: Offset(-2, -1))
      ],
      gradient: LinearGradient(
        colors: <Color>[
          Color(0xFFEEEEEE),
          Color(0xFF111133),
        ],
        stops: <double>[0.1, 1.0],
      ),
    ),
    sliver: SliverList(
      delegate: SliverChildBuilderDelegate(
          (_, index) => Padding(
                padding: const EdgeInsets.all(8.0),
                child: Center(
                    child: Text(
                  '张风捷特烈-$index',
                  style: TextStyle(fontSize: 24, color: Colors.white),
                )),
              ),
          childCount: 128),
    ),
  ),
),

到这里,五个新的 Sliver 组件就介绍完毕了,总的来说这五个都是非常有用,而且使用起来并不复杂。可以解决一些特定的滑动问题。本文的组件使用案例将会集成到 FlutterUnit 中,欢迎大家对项目多多关照。那本文就到这里,谢谢观看~


尾声:

笔者将在 bilibli 不定期发布一些视频教程,欢迎大家可以关注和支持。另外公众号也可以关注一下,也会发布一些文章。

bilibli 账号: 张风捷特烈 公众号: 编程之王

转载自:https://juejin.cn/post/7268228858762870784
评论
请登录