共计 4616 个字符,预计需要花费 12 分钟才能阅读完成。
flutter sliver 多种滚动组合开发指南
视频
https://youtu.be/4mho1kZ_YQU
https://www.bilibili.com/video/BV1WW4y1d7ZC/
前言
有不少同学工作中遇到须要把几个不同滚动行为组件(顶部 appBar、内容固定块、tabBar 切换、tabBarView 视图、自适应高度、横向滚动)黏贴成一个组件。
这时候就须要 sliver 出场了,本文将会写一个多种滚动的组合。
业务场景剖析
上面是淘宝、小红书的常见状况。
原文 https://ducafecat.com/blog/flutter-sliver-scroll
知识点 sliver
Sliver
是 Flutter 中用于构建可滚动视图的根本构建块之一。Sliver
是可滚动区域中的一小部分,具备固定的大小和地位,能够依据须要动静加载和卸载。Sliver
通常用于创立高性能、高度灵便的可滚动视图,例如列表、网格、瀑布流等。
在 Flutter 中,有许多不同类型的 Sliver
组件,每个组件都有特定的作用和用处。上面是一些常见的 Sliver
组件:
SliverAppBar
:一个带有滚动成果的利用栏,能够在向上滚动时暗藏,并在向下滚动时显示。SliverList
:将子组件搁置在一个垂直列表中,能够依据须要动静加载和卸载列表项。SliverGrid
:将子组件搁置在一个网格中,能够依据须要动静加载和卸载网格项。SliverPadding
:为子组件提供填充,以使它们与其余Sliver
组件的大小和地位保持一致。SliverToBoxAdapter
:将一个一般的组件包装成一个Sliver
组件,以便将其搁置在CustomScrollView
中。
参考
步骤
第一步:Sliver 横向滚动
lib/page.dart
Widget _mainView() { | |
return CustomScrollView( | |
slivers: [ | |
// 横向滚动 | |
SliverToBoxAdapter( | |
child: SizedBox( | |
height: 100, | |
child: PageView( | |
children: [ | |
Container( | |
color: Colors.yellow, | |
child: const Center(child: Text('横向滚动')), | |
), | |
Container(color: Colors.green), | |
Container(color: Colors.blue), | |
], | |
), | |
), | |
), | |
... |
SliverToBoxAdapter 进行包装能力 slivers 应用。
@override | |
Widget build(BuildContext context) { | |
return Scaffold(appBar: AppBar(title: const Text('Sliver Scroll')), | |
body: _mainView(),); | |
} |
第二步:固定高度的 tabView
return CustomScrollView( | |
slivers: [ | |
... | |
// 固定高度内容 | |
SliverToBoxAdapter( | |
child: Container( | |
height: 200, | |
color: Colors.greenAccent, | |
child: const Center(child: Text('固定高度内容')), | |
), | |
), |
// tabView 内容 | |
SliverToBoxAdapter( | |
child: DefaultTabController( | |
length: 3, | |
child: Column( | |
children: [ | |
const TabBar( | |
tabs: [Tab(text: 'Tab 1'), | |
Tab(text: 'Tab 2'), | |
Tab(text: 'Tab 3'), | |
], | |
), | |
SizedBox( | |
height: 200, | |
child: TabBarView( | |
children: [Container(color: Colors.yellow), | |
Container(color: Colors.green), | |
Container(color: Colors.blue), | |
], | |
), | |
), | |
], | |
), | |
), | |
), |
外层嵌套 DefaultTabController,能力让 TabBar、TabBarView 顺利工作。
第三步:自适应高度的 tabView
实现 SliverPersistentHeaderDelegate 抽象类
class _SliverDelegate extends SliverPersistentHeaderDelegate { | |
_SliverDelegate({ | |
required this.minHeight, | |
required this.maxHeight, | |
required this.child, | |
}); | |
final double minHeight; // 最小高度 | |
final double maxHeight; // 最大高度 | |
final Widget child; | |
@override | |
double get minExtent => minHeight; | |
@override | |
double get maxExtent => max(maxHeight, minHeight); | |
@override | |
Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) {return SizedBox.expand(child: child); | |
} | |
@override // 是否须要重建 | |
bool shouldRebuild(_SliverDelegate oldDelegate) { | |
return maxHeight != oldDelegate.maxHeight || | |
minHeight != oldDelegate.minHeight || | |
child != oldDelegate.child; | |
} | |
} |
编写固定头部 sliver 组件
Widget _buildPersistentHeader(Widget child, | |
{double? minHeight, double? maxHeight}) => | |
SliverPersistentHeader( | |
pinned: true, | |
delegate: _SliverDelegate( | |
minHeight: minHeight ?? 40.0, | |
maxHeight: maxHeight ?? 40.0, | |
child: child, | |
)); |
定义 TabController
class _MyPageViewState extends State<MyPageView> with TickerProviderStateMixin {...
混入 TickerProviderStateMixin
late TabController _tabController;
@override | |
void initState() {_tabController = TabController(length: 3, vsync: this); | |
super.initState();} |
@override | |
void dispose() {_tabController.dispose(); // 开释内存 | |
super.dispose();} |
退出 slivers
Widget _mainView() { | |
return CustomScrollView( | |
slivers: [ | |
... | |
// TabBar 固定 | |
_buildPersistentHeader(TabBar( | |
controller: _tabController, | |
tabs: const [Tab(text: 'Tab 1'), | |
Tab(text: 'Tab 2'), | |
Tab(text: 'Tab 3'), | |
], | |
)), |
应用 SliverFillRemaining 来撑开残余空间
// TabBarView 自适应高度 | |
SliverFillRemaining( | |
child: TabBarView( | |
controller: _tabController, | |
children: [ | |
// 第一个选项卡的内容 | |
ListView.builder( | |
itemCount: 20, | |
itemBuilder: (BuildContext context, int index) {return ListTile(title: Text('Item $index')); | |
}, | |
), | |
// 第二个选项卡的内容 | |
ListView.builder( | |
itemCount: 10, | |
itemBuilder: (BuildContext context, int index) {return ListTile(title: Text('Item $index')); | |
}, | |
), | |
// 第三个选项卡的内容 | |
ListView.builder( | |
itemCount: 5, | |
itemBuilder: (BuildContext context, int index) {return ListTile(title: Text('Item $index')); | |
}, | |
), | |
], | |
), | |
), |
SliverFillRemaining
是一个能够填充残余空间的 sliver 组件,它能够将子组件搁置在视图区域的残余空间中,并主动调整子组件的大小以填充整个空间。通常状况下,SliverFillRemaining
用于在滚动视图中搁置一个占满整个视图区域的组件,例如底部栏或页脚。
第四步:子 tabBar
还能够退出子 tabBar 组成父子选项切换
// 子 TabBar 固定 | |
_buildPersistentHeader(TabBar( | |
controller: _tabController, | |
tabs: const [Tab(text: 'subTab 1'), | |
Tab(text: 'subTab 2'), | |
Tab(text: 'subTab 3'), | |
], | |
)), |
父子 tabBar 两头再加一个固定块,查看滚动成果
// 固定高度内容 | |
SliverToBoxAdapter( | |
child: Container( | |
height: 100, | |
color: Colors.greenAccent, | |
child: const Center(child: Text('固定高度内容')), | |
), | |
), |
最初:底部再退出 SliverList
咱们在底部再加一个 list 模块,看看成果。
Widget _mainView() { | |
return CustomScrollView( | |
slivers: [ | |
... | |
// 固定高度内容 | |
SliverToBoxAdapter( | |
child: Container( | |
height: 200, | |
color: Colors.greenAccent, | |
child: const Center(child: Text('固定高度内容')), | |
), | |
), | |
// 列表 100 行 | |
SliverList( | |
delegate: SliverChildBuilderDelegate((BuildContext context, int index) {return ListTile(title: Text('Item $index')); | |
}, | |
childCount: 100, | |
), | |
), |
代码
https://github.com/ducafecat/flutter_develop_tips/tree/main/flutter_application_sliver_scroll
小结
应用 Sliver
组件后咱们的确把几种滚动给黏贴上了,然而不难发现过于简单的滚动,用户体验方面还是要思考的。
不能只为了沉积性能。
感激浏览本文
如果我有什么错?请在评论中让我晓得。我很乐意改良。
© 猫哥
ducafecat.com
end