前言

在上一篇文章中,咱们了解了Flutter SliversSliverToBoxAdapterSliverPersistentHeaderSliverFixedExtentList等常用的组件。本章则是一些不那么常用的Slivers组件,大家仅需快速阅读一遍,有个形象即可,方便遇到一些业务时,能快速定位到需求运用的组件。

SliverLayoutBuilder

依据Box协议的组件布局中,常常会运用LayoutBuilder,由于能够经过它获取在布局进程中父组件的约束,然后就能够依据约束信息动态的创建布局。例如:

LayoutBuilder(
  builder: (BuildContext context, BoxConstraints constraints) {
    if (constraints.maxWidth < 200) {
      // 最大宽度小于200,显示一张图片
      return Image.network("");
    } else {
      return Container();
    }
  },
),

那么在slivers中对应的就是SliverLayoutBuilder,能够经过SliverLayoutBuilder创建一个折叠的sliver widget树,依据组件的约束条件供给不同子组件。

重识Flutter 非常用Slivers组件速览 - part3

CustomScrollView(
        slivers: [
          SliverLayoutBuilder(
              builder: (BuildContext context, SliverConstraints constraints) {
            if (constraints.userScrollDirection == ScrollDirection.forward) {
              _color = Colors.blue; //向下滑动显示蓝色
            } else if (constraints.userScrollDirection ==
                ScrollDirection.idle) {
              _color = Colors.yellow; //正常显示黄色
            } else {
              _color = Colors.purple; //向上滑动显示紫色
            }
            return SliverToBoxAdapter(
              child: Container(
                height: 200,
                color: _color,
              ),
            );
          }),
          SliverList(
              delegate:
                  SliverChildBuilderDelegate(childCount: 20, (ctx, index) {
            return Container(
              color: Colors.primaries[index % Colors.primaries.length],
              height: 50,
            );
          }))
        ],
      ),

重识Flutter 非常用Slivers组件速览 - part3

SliverAnimatedList

在一个有很多子Item的列表中,假如用户需求删去或增加事情,假如没有任何过渡动画,那么很有可能会让用户混淆刚刚发生的工作,不知道列表item是否增加或删去了。所以为了解决这样的问题,能够运用AnimatedContainer这样带动画的组件,而在Slivers中,能够运用SliverAnimatedList,经过SliverAnimatedListState用于动态刺进item或删去item。让咱们经过一个比如来学习SliverAnimatedList

重识Flutter 非常用Slivers组件速览 - part3

增加SliverAnimatedList

这儿_listKey是一个SliverAnimatedListStateGlobalKey类型。该GlobalKey有助于刺进和删去列表项。initialItemCount是界说列表初始化有几个itemitemBuilder是需求延迟构建的组件。

final GlobalKey<SliverAnimatedListState> _listKey =
      GlobalKey<SliverAnimatedListState>();
SliverAnimatedList(
  key: _listKey,
  initialItemCount: _list.length,
  itemBuilder: _buildItem,
),

再来看下_buildItem:该index参数指示项目在列表中的方位。参数的值index将介于0和initialItemCount加上已刺进insertItem的项目总数和减去已删去removeItem的项目总数。

Widget _buildItem(
    BuildContext context, int index, Animation<double> animation) {
  return CardItem(
    animation: animation,
    item: _list[index],
    selected: _selectedItem == _list[index],
    onTap: () {
      setState(() {
        _selectedItem = _selectedItem == _list[index] ? null : _list[index];
      });
    },
  );
}

实现将刺进列表的_insert函数和从列表中删去的_remove函数

void _insert() {
  final int index =
      _selectedItem == null ? _list.length : _list.indexOf(_selectedItem!);
	//增加
	_list.insert(index, _nextItem++);
	//更新UI
	_listKey.currentState!.insertItem(index);
}
void _remove() {
    final int index = _selectedItem == null
        ? _list.length - 1
        : _list.indexOf(_selectedItem!);
    _list.removeAt(index);
//之所以需求这个方法,是由于移除的item在动画完结之前都是可见的。
    _listKey.currentState!.removeItem(
      index,
      (context, animation) => SizeTransition(
        sizeFactor: animation,
        child: Card(
          child: Center(
            child: Text(
              'Item $index',
              style: Theme.of(context).textTheme.headline4,
            ),
          ),
        ),
      ),
    );
    setState(() {
      _selectedItem = null;
    });
}

具体代码详见:点击跳转github详情代码地址

SliverOpacity

运用Opacity能够使组件变得透明,而在slivers中能够运用SliverOpacity。它们的不同之处只在于:Opacity适用于依据Box协议的组件,SliverOpacity适用于依据sliver协议的组件。

重识Flutter 非常用Slivers组件速览 - part3

可操控特点有:

opacity: 它一般取值介于0.0到之间1.0。当值为 0.0,则不会制作 sliver child,若值为1.0,则会立即制作 sliver child。除了0.01.0之外,运用其他的值是非常昂贵的,例如0.5,由于需求将sliver child 制作到缓冲区中。

alwaysIncludeSemantics:是否总是包含语义信息,默许是 false。该特点主要是用于辅助访问的 关于视障人员来说会更友爱。假如特点的值是 true,则不论透明度是多少,都会显示语义信息(能够辅助朗读)。

运用也非常简略:

重识Flutter 非常用Slivers组件速览 - part3

bool _isVisible = true;
...
CustomScrollView(
  slivers: [
    SliverOpacity(
      opacity: _isVisible ? 1.0 : 0.0,
      sliver: SliverList(
        delegate: SliverChildListDelegate(
          [
            Container(
              height: 50,
              color: Colors.green,
              child: Center(
                child: Text(
                  "Taxze & SliverOpacity",
                  style: TextStyle(fontSize: 20, color: Colors.white),
                ),
              ),
            ),
          ],
        ),
      ),
    ),
    SliverPadding(
      padding: EdgeInsets.only(top: 24),
      sliver: SliverToBoxAdapter(
        child: FloatingActionButton(
          child: const Icon(Icons.flip),
          onPressed: () {
            setState(() {
              _isVisible = !_isVisible;
            });
          },
        ),
      ),
    )
  ],
),

SliverAnimatedOpacity

假如运用SliverOpacity,那么组件的不透明度会直接从0.0跳到1.0,转变的进程看起来不光滑。为了让Opacity滑润的过渡,能够运用SliverAnimatedOpacity

重识Flutter 非常用Slivers组件速览 - part3

重识Flutter 非常用Slivers组件速览 - part3

bool _visible = true;
CustomScrollView(
  slivers: [
    SliverAnimatedOpacity(
      //动画履行完毕
      onEnd: () => print("动画完结"),
      curve: Curves.linear,
      opacity: _visible ? 1.0 : 0.0,
      duration: const Duration(seconds: 2),
      sliver: SliverFixedExtentList(
          delegate: SliverChildBuilderDelegate(
              (BuildContext context, int index) {
            return Image.network(
                "https://p3-passport.byteimg.com/img/user-avatar/af5f7ee5f0c449f25fc0b32c050bf100~180x180.awebp");
          }, childCount: 1),
          itemExtent: 200.0),
    ),
    SliverPadding(
      padding: EdgeInsets.only(top: 18),
      sliver: SliverToBoxAdapter(
          child: FloatingActionButton(
        onPressed: () {
          setState(() {
            _visible = !_visible;
          });
        },
        tooltip: 'Toggle opacity',
        child: const Icon(Icons.flip),
      )),
    ),
  ],
),

SliverFadeTransition

这也是运用opacitysliver组件设置动画的。仅有的区别是,运用Animation<double>值而不是double值。

重识Flutter 非常用Slivers组件速览 - part3

class _SliverPart3SliverFadeTransitionState
    extends State<SliverPart3SliverFadeTransition>
    with SingleTickerProviderStateMixin {
  late final AnimationController controller = AnimationController(
    duration: const Duration(milliseconds: 1000),
    vsync: this,
  );
  late final Animation<double> animation = CurvedAnimation(
    parent: controller,
    curve: Curves.easeIn,
  );
  @override
  void initState() {
    super.initState();
    animation.addStatusListener((AnimationStatus status) {
      if (status == AnimationStatus.completed) {
        controller.reverse();
      } else if (status == AnimationStatus.dismissed) {
        controller.forward();
      }
    });
    controller.forward();
  }
  @override
  Widget build(BuildContext context) {
    return CustomScrollView(slivers: <Widget>[
      SliverAppBar(
        title: Text('SliverPart3SliverFadeTransition'),
        pinned: true,
      ),
      SliverFadeTransition(
          opacity: animation,
          sliver: SliverToBoxAdapter(
            child: Center(
              child: Image.network(
                "https: //p3-passport.byteimg.com/img/user-avatar/af5f7ee5f0c449f25fc0b32c050bf100~180x180.awebp",
                width: double.infinity,
                height: 300,
                fit: BoxFit.cover,
              ),
            ),
          ))
    ]);
  }
}

SliverVisibility

SliverVisibilityVisibility组件相同,仅仅它是依据sliver协议的组件。

重识Flutter 非常用Slivers组件速览 - part3

SliverVisibility有许多的参数,如:

  • maintainAnimation: 用于判别animations不行见时是否保持在sliver子树内。
  • maintainInteractivity : 用于判别sliver隐藏时是否允许交互。
  • maintainSemantics : 用于确定隐藏时是否保持sliver的语义。
  • maintainSize: 用于确定是否为sliver所在的方位保留空间。
  • maintainState : 用于判别不行见时是否保护sliver子树的State目标。
  • replacementSliver:sliver 不行见时,此处界说的 Widget 可见。

一个简略的比如来了解SliverVisibility:

重识Flutter 非常用Slivers组件速览 - part3

bool _visible = true;
CustomScrollView(
  slivers: <Widget>[
    SliverVisibility(
        visible: _visible,
        replacementSliver: SliverToBoxAdapter(
          child: Container(
            width: double.infinity,
            height: 300,
            color: Colors.brown,
            child: Center(
              child: Text(
                "Image is hidden. Tap below button to show",
                style: TextStyle(color: Colors.white),
              ),
            ),
          ),
        ),
        sliver: SliverToBoxAdapter(
          child: Image.network(
            "https://p3-passport.byteimg.com/img/user-avatar/af5f7ee5f0c449f25fc0b32c050bf100~180x180.awebp",
            width: double.infinity,
            height: 300,
            fit: BoxFit.cover,
          ),
        )),
    SliverPadding(
      padding: EdgeInsets.only(top: 18),
      sliver: SliverToBoxAdapter(
          child: FloatingActionButton(
        onPressed: () {
          setState(() {
            _visible = !_visible;
          });
        },
        tooltip: 'Toggle visibility',
        child: Icon(!_visible ? Icons.visibility : Icons.visibility_off),
      )),
    ),
  ],
),

SliverIgnorePointer

假如期望sliver疏忽点击或其他任何类型的交互时,只需将sliver组件包裹在里面SliverIgnorePointer。它将禁用该小部件的交互。

重识Flutter 非常用Slivers组件速览 - part3

ignoring特点为true时,组件不行交互。当ignoringSemantics特点为true时,子树将对Semantics(语义)层不行见。

就用SliverVisibility组件的比如,只需求在操控按钮上,包裹上一层SliverIgnorePointer即可疏忽点击事情。

SliverIgnorePointer(
  sliver: SliverPadding(
    padding: EdgeInsets.only(top: 18),
    sliver: SliverToBoxAdapter(
        child: FloatingActionButton(
      onPressed: () {
        setState(() {
          _visible = !_visible;
        });
      },
      tooltip: 'Toggle visibility',
      child:
          Icon(!_visible ? Icons.visibility : Icons.visibility_off),
    )),
  ),
),

SliverSafeArea

假如你从前运用过SafeArea,那么SliverSafeArea除了它依据sliver协议外,它也在做同样的工作。例如当你想要显示一篇长文章时,便可运用SliverSafeArea来避免 iPhone X 上的缺口或其他相似的。

SliverSafeArea(sliver: SliverList(
  delegate: SliverChildBuilderDelegate((ctx, index) {
    return Container(
      color: Colors.primaries[index % Colors.primaries.length],
      height: 100,
    );
  },childCount: 20),
))

尾述

三篇文章,从为什么要运用Sliver,再依据运用频率逐一解析Slivers系列的组件。信任您已经入门了Sliver的世界。那么鄙人一章,将独自详解NestedScrollView,包括SliverOverlapAbsorber SliverOverlapInjector…的优化

关于我

Hello,我是Taxze,假如您觉得文章对您有价值,期望您能给我的文章点个❤️,有问题需求联络我的话:我在这儿,也能够经过的新的私信功用联络到我。假如您觉得文章还差了那么点东西,也请经过重视督促我写出更好的文章~万一哪天我前进了呢?