美文网首页
Sliver系列组件入门使用记录

Sliver系列组件入门使用记录

作者: windyfat | 来源:发表于2020-08-27 19:07 被阅读0次

    在开发的过程中比较常用的是ListView和GridView,但是如果是复杂一些的页面,单纯的ListView和GridView就不够用了。而Flutter提供了Sliver系列组件来实现复杂的滚动页面,这里就是学习的过程中所作的记录,都是入门级别的,比较简单。
    Demo地址位于文章末尾。
    下面就开始正文了。


    SliverList和SliverGrid

    SliverList只有一个属性:delegate,类型是SliverChildDelegate。SliverChildDelegate是一个抽象类,不能直接使用。Flutter中定义好了两个继承于SliverChildDelegate的类对象,可以直接用,分别是:SliverChildListDelegateSliverChildBuilderDelegate

    先来看SliverChildListDelegate,声明如下:

    SliverChildListDelegate(
        this.children, {
        ...
      })
    

    只有一个必填属性children,是一个类型为Widget的List集合。其他属性几乎不用,暂时忽略。跟ListView构造函数相同,会将所有的子组件一次性的全部渲染出来。
    SliverChildBuilderDelegate则跟ListView.build构造函数类似,需要时才会创建,提高了性能。

    const SliverChildBuilderDelegate(
        this.builder, {
        this.childCount,
        ...
      })
    

    主要参数是builder,是一个返回值为Widget的函数,原型如下:

    Widget Function(BuildContext context, int index)
    

    这个比较简单就不记录了。

    SliverFixedExtentList是固定item高度的SliverList,只是比SliverList多了一个参数itemExtent来设置item高度,其用法跟SliverList一致。

    SliverGrid有两个属性:delegategridDelegate。其中delegate跟上面的用法一样,gridDelegate的类型是SliverGridDelegate
    SliverGridDelegate是一个抽象类,定义了子控件Layout相关的接口。Flutter中提供了两个SliverGridDelegate的子类SliverGridDelegateWithFixedCrossAxisCount和SliverGridDelegateWithMaxCrossAxisExtent,可以直接使用。下面分别介绍一下。

    SliverGridDelegateWithFixedCrossAxisCount

    该类实现了一个横轴方向上固定子控件数量的layout的算法,构造函数为:

    SliverGridDelegateWithFixedCrossAxisCount({
      @required double crossAxisCount, 
      double mainAxisSpacing = 0.0,
      double crossAxisSpacing = 0.0,
      double childAspectRatio = 1.0,
    })
    
    • crossAxisCount:横轴子元素的数量。此属性值确定后子元素在横轴的长度就确定了,即横轴长度除以crossAxisCount的商。
    • mainAxisSpacing:主轴方向的间距。
    • crossAxisSpacing:横轴方向子元素的间距。
    • childAspectRatio:子元素在横轴长度和主轴长度的比例。由于crossAxisCount指定后,子元素横轴长度就确定了,然后通过此参数值就可以确定子元素在竖轴的长度。

    子元素的大小是通过crossAxisCount和childAspectRatio两个参数决定的。

    SliverGridDelegateWithMaxCrossAxisExtent

    该类实现了一个横轴方向上子元素为固定最大长度的layout算法,其构造函数为:

    SliverGridDelegateWithMaxCrossAxisExtent({
      double maxCrossAxisExtent,
      double mainAxisSpacing = 0.0,
      double crossAxisSpacing = 0.0,
      double childAspectRatio = 1.0,
    })
    

    maxCrossAxisExtent是子元素在横轴方向上的最大长度。之所以是最大长度而不是最终长度,这是因为子元素在横轴方向上的长度仍然是等分的。所以子元素在横轴方向上的元素个数num = 横轴长度 / maxCrossAxisExtent + 1,最终的子元素的宽度= 横轴长度 / num。其他参数和SliverGridDelegateWithFixedCrossAxisCount相同。

    SliverGrid的使用方法跟GridView的使用方法保持一致。

    SliverAnimatedList

    SliverAnimatedList是带有动画的SliverList,先来看构造函数:

    SliverAnimatedList({
        Key key,
        @required this.itemBuilder,
        this.initialItemCount = 0,
      })
    
    • initialItemCount:item的个数。
    • itemBuilder:是一个AnimatedListItemBuilder函数,原型如下:
    Widget Function(BuildContext context, int index, Animation<double> animation)
    

    使用SliverAnimatedList在添加或删除item的时候,需要通过一下方式来操作:

    1. 定义一个GlobalKey
    GlobalKey<SliverAnimatedListState> _listKey = GlobalKey<SliverAnimatedListState>(); 
    
    1. 将key赋值给SliverAnimatedList
    SliverAnimatedList(
                  key: _listKey,
                  initialItemCount: _list.length,
                  itemBuilder: _buildItem,
                )
    
    1. 通过key.currentState.insertItem或key.currentState.removeItem来进行添加或删除。
    _listKey.currentState.insertItem(_index);
    _listKey.currentState.removeItem(_index,
            (context, animation) => _buildItem(context, item, animation));
    

    _buildItem函数原型如下:

    Widget _buildItem(BuildContext context, int index, Animation<double> animation) {
        return SizeTransition(
          sizeFactor: animation,
          child: Card(
            child: ListTile(
              title: Text(
                'Item $index',
              ),
            ),
          ),
        );
      }
    

    如果想修改动画类型,就需要修改_buildItem中的动画方式。

    SliverPersistentHeader

    这个组件可以实现控件吸顶的效果。先来看构造函数:

    SliverPersistentHeader({
        Key key,
        @required this.delegate,
        this.pinned = false,
        this.floating = false,
      })
    

    其中pinned的效果就是控制header是否保持吸顶效果。另一个重要的属性则是delegate,它的类型是SliverPersistentHeaderDelegate,这是一个抽象类,所以要使用的话,需要自己定义一个子类。
    子类需要重写4个父类的函数:

    @override
      Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) {
        // TODO: implement build
        throw UnimplementedError();
      }
    
      @override
      // TODO: implement maxExtent
      double get maxExtent => throw UnimplementedError();
    
      @override
      // TODO: implement minExtent
      double get minExtent => throw UnimplementedError();
    
      @override
      bool shouldRebuild(SliverPersistentHeaderDelegate oldDelegate) {
        // TODO: implement shouldRebuild
        throw UnimplementedError();
      }
    

    其中build返回header显示的内容,maxExtentminExtent表示最大值和最小值,即header展开和闭合时的高度,若相同则header高度保持不变,若不同,则滚动的时候header的高度会自动在两只之间进行变化。shouldRebuild表示是否需要重新绘制,需要的话则返回true。
    代码如下:

    CustomScrollView(
            slivers: <Widget>[
              // makeHeader('Header Section 1'),
              SliverPersistentHeader(
                pinned: true,
                delegate: _SliverAppBarDelegate(// 自定义的delegate
                  minHeight: 60.0,
                  maxHeight: 60.0,
                  child: Container(
                    color: Colors.white,
                    child: Center(
                      child: Text('Header Section 1'),
                    ),
                  ),
                ),
              ),
              SliverGrid.count(
                crossAxisCount: 3,
                children: [
                  Container(color: Colors.red, height: 150.0),
                  Container(color: Colors.purple, height: 150.0),
                  Container(color: Colors.green, height: 150.0),
                  Container(color: Colors.orange, height: 150.0),
                  Container(color: Colors.yellow, height: 150.0),
                  Container(color: Colors.pink, height: 150.0),
                  Container(color: Colors.cyan, height: 150.0),
                  Container(color: Colors.indigo, height: 150.0),
                  Container(color: Colors.blue, height: 150.0),
                ],
              ),
            ],
          )
    

    通过SliverPersistentHeader可以实现SliverAppBar的效果。

    SliverAppBar

    先来看构造函数:

    SliverAppBar({
        this.flexibleSpace,
        this.forceElevated = false,
        this.expandedHeight,
        this.floating = false,
        this.pinned = false,
        this.snap = false,
        this.stretch = false,
        this.stretchTriggerOffset = 100.0,
        this.onStretchTrigger,
        ...
      })
    

    其他的参数都跟AppBar是一致的,就忽略了。其中有一些重要的参数:

    • expandedHeight:展开时AppBar的高度。
    • flexibleSpace:空间大小可变的组件。
    • floating:向上滚动时,AppBar会跟随着滑出屏幕;向下滚动时,会有限显示AppBar,只有当AppBar展开时才会滚动ListView。
    • pinned:当SliverAppBar内容滑出屏幕时,将始终渲染一个固定在顶部的收起状态AppBar。
    • snap:当手指离开屏幕时,AppBar会保持跟手指滑动方向相一致的状态,即手指上滑则AppBar收起,手指下滑则AppBar展开。
    • stretch:是否拉伸。

    只有floating设置为true时,snap才可以设置为true。

    FlexibleSpaceBar是Flutter提供的一个现成的空间大小可变的组件,并且处理好了title和background的过渡效果。重点说一下其中的stretchModes属性,这个是用来设置AppBar拉伸效果的,有三个枚举值,可以互相搭配使用,但是前提是stretch为true。

    • blurBackground:拉伸时使用模糊效果。
    • fadeTitle:拉伸时标题将消失。
    • zoomBackground默认值,拉伸时widget将填充额外的空间。

    SliverFillRemaining和SliverFillViewport

    SliverFillRemaining会自动充满视图的全部空间,通常用于slivers的最后一个。
    SliverFillViewport 生成的每一个item都占满全屏。
    用法都比较简单,就没有记录。
    详细可查看demo

    SliverOpacity和SliverPadding

    SliverOpacity用来设置子控件透明度,构造函数如下:

    SliverOpacity({
        Key key,
        @required this.opacity,
        this.alwaysIncludeSemantics = false,
        Widget sliver,
      })
    

    SliverPadding是设置需要padding的Sliver控件,其构造函数如下:

    SliverPadding({
        Key key,
        @required this.padding,
        Widget sliver,
      })
    

    SliverOpacity 和SliverPadding 中的sliver属性的值必须是Sliver系列的Widget。

    SliverPrototypeExtentList

    跟SliverList用法基本一致,但是子控件的高度是由prototypeItem的控件高度决定的。构造函数如下:

    SliverPrototypeExtentList({
        Key key,
        @required SliverChildDelegate delegate,
        @required this.prototypeItem,
      })
    

    SliverLayoutBuilder

    理解有限,就不记录贻笑大方了。
    可查看大佬的文章: Flutter Sliver一辈子之敌 (ExtendedList)

    如果在CustomScrollView中用到了其他非Sliver系列的组件,需要使用SliverToBoxAdapter将这些组件包裹起来。

    参考文章如下:
    1、在Flutter中创建有意思的滚动效果 - Sliver系列
    2、Slivers, Demystified

    Demo地址点击跳转

    相关文章

      网友评论

          本文标题:Sliver系列组件入门使用记录

          本文链接:https://www.haomeiwen.com/subject/fxrhsktx.html