Flutter Sliver系列组件入门
  xx2YH4ad7R0N 2023年11月02日 68 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显示的内容,​​maxExtent​​​和​​minExtent​​​表示最大值和最小值,即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地址:​​点击跳转​


延伸

在Flutter中创建有意思的滚动效果 - Sliver系列

1. 前言

​Flutter​​​作为时下最流行的技术之一,凭借其出色的性能以及抹平多端的差异优势,早已引起大批技术爱好者的关注,甚至一些​​闲鱼​​​,​​美团​​​,​​腾讯​​​等大公司均已投入生产使用。虽然目前其生态还没有完全成熟,但身靠背后的​​Google​​​加持,其发展速度已经足够惊人,可以预见将来对​​Flutter​​开发人员的需求也会随之增长。

无论是为了技术尝鲜还是以后可能的工作机会,都9102年了,作为一个前端开发者,似乎没有理由不去尝试它。正是带着这样的心理,笔者也开始学习​​Flutter​​​,同时建了一个用于练习的​​仓库​​,后续所有代码都会托管在上面,欢迎star,一起学习。这是我写的Flutter系列文章:

在之前的文章中,我们学习了如何使用​​ListView​​​和​​GridView​​​这两个滚动类型组件。今天,我们就来学习另一个滚动组件​​CustomScrollView​​​及其搭配使用的​​Sliver​​系列组件。掌握了它们,你就可以做一些有趣的滚动效果啦~

2. 必备知识

在进入今天的正题之前,我们先来简单了解下今天的两个主角​​CustomScrollView​​​和​​Sliver​​​:​​CustomScrollView​​​是​​Flutter​​​提供的可以用来自定义滚动效果的组件,它可以像胶水一样将多个​​Sliver​​粘合在一起。

什么意思呢?举个栗子(你也可以点击​​这里​​​看​​youtube​​上的一个视频):

假如页面中同时存在一个​​List​​​和一个​​Grid​​,虽然它们看起来是一个整体,但是由于各自的滚动效果是分离的,所以没法保证一致的滚动效果。

而使用​​CustomScrollView​​​组件作为滚动容器,​​SliverList​​​和​​SliverGrid​​​分别替代​​List​​​和​​Grid​​​作为​​CustomScrollView​​​的子组件,滚动效果再由​​CustomScrollView​​统一控制,这样就可以了。

其中​​SliverList​​​和​​SliverGrid​​​就是我们前面提到的​​Sliver​​​系列中的两员,除此之外,​​Sliver​​家族还有常用的几个:

  • ​SliverAppBar​​:Creates a material design app bar that can be placed in a CustomScrollView.
  • ​SliverPersistentHeader​​:Creates a sliver that varies its size when it is scrolled to the start of a viewport.
  • ​SliverFillRemaining​​:Creates a sliver that fills the remaining space in the viewport.
  • ​SliverToBoxAdapter​​:Creates a sliver that contains a single box widget.
  • ​SliverPadding​​:Creates a sliver that applies padding on each side of another sliver.

注意:由于​​CustomeScrollView​​​的子组件只能是​​Sliver​​​系列,所以如果你想将一个普通组件塞进​​CustomScrollView​​​,那么务必将该组件用​​SliverToBoxAdapter​​包裹。

3. 热身:SliverList / SliverGrid

前面讲了那么多的概念似乎有些枯燥,接下来就让我们从最简单的一个例子入手来看看如何使用​​CustomScrollView​​​和​​SliverList​​​/​​SliverGrid​​。

其实​​CustomScrollView​​​的用法很简单,它有一个​​slivers​​​属性,是一个​​Widget​​​数组,将子组件都放在里面就可以了,其他的一些滚动相关的属性基本和我们之前学到的​​ListView​​差不多。

CustomScrollView(
slivers: <Widget>[
renderSliverA(),
renderSliverB(),
renderSliverC(),
],
)

再来看看​​SliverList​​​,它只有一个​​delegate​​​属性,可以用​​SliverChildListDelegate​​​或​​SliverChildBuilderDelegate​​​这两个类实现。前者将会一次性全部渲染子组件,后者将会根据视窗渲染当前出现的元素,其效果可以和​​ListView​​​和​​ListView.build​​这两个构造函数类比。

SliverList(
delegate: SliverChildListDelegate(
<Widget>[
renderA(),
renderB(),
renderC(),
]
)
)

SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) => renderItem(context, index),
childCount: 10,
)
)

通过上面的例子我们发现​​SliverList​​​的使用方式和​​ListView​​​大同小异,而​​SliverGrid​​也是如此,这里就不再过多赘述,来看个两列网格的例子:

SliverGrid.count(
crossAxisCount: 2,
children: <Widget>[
renderA(),
renderB(),
renderC(),
renderD()
]
)

接下来,就让我们通过一个实际例子将上面的三点结合在一起。

代码(完整版看这里

final List<Color> colorList = [
Colors.red,
Colors.orange,
Colors.green,
Colors.purple,
Colors.blue,
Colors.yellow,
Colors.pink,
Colors.teal,
Colors.deepPurpleAccent
];

// Text组件需要用SliverToBoxAdapter包裹,才能作为CustomScrollView的子组件
Widget renderTitle(String title) {
return SliverToBoxAdapter(
child: Padding(
padding: EdgeInsets.symmetric(vertical: 16),
child: Text(
title,
textAlign: TextAlign.center,
style: TextStyle(fontSize: 20),
),
),
);
}

CustomScrollView(
slivers: <Widget>[
renderTitle('SliverGrid'),
SliverGrid.count(
crossAxisCount: 3,
children: colorList.map((color) => Container(color: color)).toList(),
),
renderTitle('SliverList'),
SliverFixedExtentList( // SliverList的语法糖,用于每个item固定高度的List
delegate: SliverChildBuilderDelegate(
(context, index) => Container(color: colorList[index]),
childCount: colorList.length,
),
itemExtent: 100,
),
],
)

效果图:  

Flutter Sliver系列组件入门_flutter

 

上面的例子中还有一点需要注意的是:我们将标题组件放在了​​SliverToBoxAdapter​​​内,因为​​CustomScrollView​​​只接受​​Sliver​​系列的组件。

4. 眼前一亮的SliverAppBar

​AppBar​​​是常用来构建一个页面头部​​Bar​​​的组件,在​​CustomScrollView​​​中与其对应的是​​SliverAppBar​​​组件。它有什么神奇之处呢?随着页面的滚动,头部​​Bar​​将会有一个收起过渡的效果。我们先来看下效果:

float效果

snap效果

pinned效果

Flutter Sliver系列组件入门_flutter_02

 


Flutter Sliver系列组件入门_滚动效果_03


Flutter Sliver系列组件入门_flutter_04

 


通过上面的预览图,想必你肯定很好奇​​SliverAppBar​​中的过渡效果是如何实现的~先别急,我们先来看下应该如何使用它:

SliverAppBar(
floating: true,
snap: true,
pinned: true,
expandedHeight: 250,
flexibleSpace: FlexibleSpaceBar(
title: Text(this.title),
background: Image.network(
'http://img1.mukewang.com/5c18cf540001ac8206000338.jpg',
fit: BoxFit.cover,
),
),
)

​SliverAppBar​​最重要的几个属性在上面的例子中罗列出来。其中:

  • ​expandedHeight​​​:展开状态下​​appBar​​的高度,即图中图片所占空间;
  • ​flexibleSpace​​​:空间大小可变的组件,​​Flutter​​​给我们提供了一个现成的​​FlexibleSpaceBar​​​组件,给我们处理好了​​title​​过渡的效果。

另外,​​floating​​​/​​snap​​​/​​pinned​​​这三个属性可以指定​​SliverAppBar​​内容滑出屏幕之后的表现形式。

  • ​float​​​:向下滑动时,即使当前​​CustomScrollView​​​不在顶部,​​SliverAppBar​​也会跟着一起向下出现;
  • ​snap​​​:当手指放开时,​​SliverAppBar​​​会根据当前的位置进行调整,始终保持​​展开​​​或​​收起​​的状态;
  • ​pinned​​​:不同于​​float​​​效果,当​​SliverAppBar​​内容滑出屏幕时,将始终渲染一个固定在顶部的收起状态组件。

需要注意的是:​​snap​​​效果一定要在​​float​​​为​​true​​时才会生效。另外,你也可以将这三者进行组合使用。

5. 花样多变的SliverPersistentHeader

在上一小节中我们见识到了​​SliverAppBar​​​的神奇之处,其实它就是基于​​SliverPersistentHeader​​​实现的。通过​​SliverPersistentHeader​​​,我们还可以实现​​sticky​​吸顶的效果。

​SliverPersistentHeader​​​最重要的一个属性是​​SliverPersistentHeaderDelegate​​​,为此我们需要实现一个类继承自​​SliverPersistentHeaderDelegate​​。

class StickyTabBarDelegate extends SliverPersistentHeaderDelegate {

@override
double get minExtent => null;

@override
double get maxExtent => null;

@override
bool shouldRebuild(SliverPersistentHeaderDelegate oldDelegate) => null;

@override
Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) => null;
}

可以看到,​​SliverPersistentHeaderDelegate​​的实现类必须实现其4个方法。其中:

  • ​minExtent​​:收起状态下组件的高度;
  • ​maxExtent​​:展开状态下组件的高度;
  • ​shouldRebuild​​​:类似于​​react​​​中的​​shouldComponentUpdate​​;
  • ​build​​:构建渲染的内容。

接下来,我们就来实现一个​​TabBar​​吸顶的效果。

代码(完整版看这里

CustomScrollView(
slivers: <Widget>[
SliverAppBar(
// ...
),
SliverPersistentHeader( // 可以吸顶的TabBar
pinned: true,
delegate: StickyTabBarDelegate(
child: TabBar(
labelColor: Colors.black,
controller: this.tabController,
tabs: <Widget>[
Tab(text: 'Home'),
Tab(text: 'Profile'),
],
),
),
),
SliverFillRemaining( // 剩余补充内容TabBarView
child: TabBarView(
controller: this.tabController,
children: <Widget>[
Center(child: Text('Content of Home')),
Center(child: Text('Content of Profile')),
],
),
),
],
)

class StickyTabBarDelegate extends SliverPersistentHeaderDelegate {
final TabBar child;

StickyTabBarDelegate({@required this.child});

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

@override
double get maxExtent => this.child.preferredSize.height;

@override
double get minExtent => this.child.preferredSize.height;

@override
bool shouldRebuild(SliverPersistentHeaderDelegate oldDelegate) {
return true;
}
}

效果图

Flutter Sliver系列组件入门_android_05

 

根据上面的图我们可以看到,当下方​​tab​​​内容滑出屏幕后,​​tabBar​​​并没有跟着一起滑走,而是粘在了顶部。可见​​SliverPersistentHeader​​​的确可以满足我们的​​sticky​​效果。

不过​​SliverPersistentHeader​​​的神奇可远不止如此哦~我们可以通过它自定义一些头部的过渡效果,毕竟​​SliverAppBar​​也是通过它实现的。就比如下方这个电影详情页的头部过渡效果,这在一般的app种还是比较常见的。

Flutter Sliver系列组件入门_android_06

 

那么这种效果要如何实现呢?关键就在于​​build​​​方法中的​​shrinkOffset​​​属性,它代表当前头部的滚动偏移量。我们可以根据它计算得到当前收起头部的​​背景颜色​​​以及图标和文案的​​字体颜色​​,这样就能根据当前位置得到过渡效果啦~

代码(完整版看这里

class SliverCustomHeaderDelegate extends SliverPersistentHeaderDelegate {
final double collapsedHeight;
final double expandedHeight;
final double paddingTop;
final String coverImgUrl;
final String title;

SliverCustomHeaderDelegate({
this.collapsedHeight,
this.expandedHeight,
this.paddingTop,
this.coverImgUrl,
this.title,
});

@override
double get minExtent => this.collapsedHeight + this.paddingTop;

@override
double get maxExtent => this.expandedHeight;

@override
bool shouldRebuild(SliverPersistentHeaderDelegate oldDelegate) {
return true;
}

Color makeStickyHeaderBgColor(shrinkOffset) {
final int alpha = (shrinkOffset / (this.maxExtent - this.minExtent) * 255).clamp(0, 255).toInt();
return Color.fromARGB(alpha, 255, 255, 255);
}

Color makeStickyHeaderTextColor(shrinkOffset, isIcon) {
if(shrinkOffset <= 50) {
return isIcon ? Colors.white : Colors.transparent;
} else {
final int alpha = (shrinkOffset / (this.maxExtent - this.minExtent) * 255).clamp(0, 255).toInt();
return Color.fromARGB(alpha, 0, 0, 0);
}
}

@override
Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) {
return Container(
height: this.maxExtent,
width: MediaQuery.of(context).size.width,
child: Stack(
fit: StackFit.expand,
children: <Widget>[
// 背景图
Container(child: Image.network(this.coverImgUrl, fit: BoxFit.cover)),
// 收起头部
Positioned(
left: 0,
right: 0,
top: 0,
child: Container(
color: this.makeStickyHeaderBgColor(shrinkOffset), // 背景颜色
child: SafeArea(
bottom: false,
child: Container(
height: this.collapsedHeight,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
IconButton(
icon: Icon(
Icons.arrow_back_ios,
color: this.makeStickyHeaderTextColor(shrinkOffset, true), // 返回图标颜色
),
onPressed: () => Navigator.pop(context),
),
Text(
this.title,
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
color: this.makeStickyHeaderTextColor(shrinkOffset, false), // 标题颜色
),
),
IconButton(
icon: Icon(
Icons.share,
color: this.makeStickyHeaderTextColor(shrinkOffset, true), // 分享图标颜色
),
onPressed: () {},
),
],
),
),
),
),
),
],
),
);
}
}

上面的代码虽然很长,但大部分是构建​​widget​​​的代码。所以,我们重点关注​​makeStickyHeaderTextColor​​​和​​makeStickyHeaderBgColor​​​即可。这两个方法都是根据当前的​​shrinkOffset​​​值计算过渡过程中的颜色值。另外,这里需要注意头部在​​iPhoneX​​​及以上的刘海头涉及,可以用​​SafeArea​​组件解决问题。

6. 总结

本文首先介绍了​​CustomScrollView​​​和​​Sliver​​​系列组件的概念及其关系,接着以​​SliverList​​​和​​SliverGrid​​​结合的示例说明了其使用方法。然后,又介绍了较常用的​​SliverAppBar​​​组件,分别解释了其​​float​​​/​​snap​​​/​​pinned​​​各自的效果。最后,讲解了​​SliverPersistentHeader​​​组件的使用方法,并用实际例子加以说明其自定义过渡效果的用法。希望通过本文的介绍,你可以用​​CustomScrollView​​​和​​Sliver​​系列组件创建出更有意思的滚动效果~

【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月08日 0

暂无评论

推荐阅读
  iD7FikcuyaVi   2023年11月30日   27   0   0 MacWindowsandroid
  b1UHV4WKBb2S   2023年11月13日   41   0   0 裁剪ideflutter
  b1UHV4WKBb2S   2023年11月13日   29   0   0 flutterDart
xx2YH4ad7R0N