NestedScrollView元件
可以在其内部嵌套其他滾動視圖的滾動視圖,其滾動位置是固有連結的。
在普通的[ScrollView]中,如果有一個Sliver元件容納了一個[TabBarView],它沿相反的方向滾動(例如,允許使用者在标簽所代表的頁面之間水準滑動,而清單則垂直滾動),則該[TabBarView]内部的任何清單都不會互相作用與外部[ScrollView]。
如:浏覽内部清單以滾動到頂部不會導緻外部[ScrollView]中的[SliverAppBar]折疊以展開。
SliverPersistentHeader元件
SliverPersistentHeader控件當滾動到邊緣時根據滾動的距離縮小高度,有點類似 SliverAppBar 的背景效果。
SliverPersistentHeader的delegate屬性
需要自定義,build傳回顯示的内容,maxExtent和minExtent表示最大和最小值,滾動的時候高度在這個範圍内變化。shouldRebuild表示是否需要更新,如果内容需要變化需要設定為true。
class StickyTabBarDelegate extends SliverPersistentHeaderDelegate {
final TabBar child;
StickyTabBarDelegate({@required this.child});
@override
Widget build(
BuildContext context, double shrinkOffset, bool overlapsContent) {
return Container(
color: Theme.of(context).backgroundColor,
child: this.child,
);
}
@override
double get maxExtent => this.child.preferredSize.height;
@override
double get minExtent => this.child.preferredSize.height;
@overridebool shouldRebuild(SliverPersistentHeaderDelegate oldDelegate) {
return true;
}
}
常用屬性:
- floating 設定為true時,向下滑動時,即使目前CustomScrollView不在頂部,SliverAppBar也會跟着一起向下出現
- pinned:設定懸停在頂部,設定為true時,當SliverAppBar内容滑出螢幕時,将始終渲染一個固定在頂部的收起狀态
FlexibleSpaceBar元件
AppBar的一部分,它可以擴充,折疊,延伸,最常用于SliverAppBar.flexibleSpace字段。
FlexibleSpaceBar中的stretchModes屬性:
參數控制拉伸區域的滾動特性:
- StretchMode.zoomBackground- >背景小部件将展開以填充額外的空間。
- StretchMode.blurBackground- >使用[ImageFilter.blur]效果,背景将模糊。
- StretchMode.fadeTitle- >随着使用者過度滾動,标題将消失。
使用stretchModes屬性需要開始stretch模式,可設定單個或者多個:
SliverAppBar(
pinned: true,
expandedHeight: 200.0,
stretch: true,
flexibleSpace: FlexibleSpaceBar(
stretchModes: [StretchMode.zoomBackground],
...
)
可以通過stretchTriggerOffset 和onStretchTrigger監聽拉伸事件,用法如下:
SliverAppBar(
stretch: true,
stretchTriggerOffset: 100,
onStretchTrigger: (){
print('onStretchTrigger');
},
...
)
注意:這個屬性是在SliverAppBar中設定,但拉伸超過100時,将會回調onStretchTrigger函數。
示例一,隐藏标題欄
import 'package:flutter/material.dart';
class NestedScrollViewDemo1 extends StatefulWidget {
@override
StatecreateState() {
return NestedScrollViewDemo1State();
}
}
class NestedScrollViewDemo1State extends State<NestedScrollViewDemo1> {
@override
Widget build(BuildContext context) {
return NestedScrollView(
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
return [
SliverAppBar(
title: Text('碼上加油站'),
)
];
},
body: SingleChildScrollView(
reverse: false,
child: Container(
color: Colors.grey,
height: 1500,
alignment: Alignment.center,
width: double.infinity,
child: Text("碼\n上\n加\n油\n站\n,\n一\n起\n來\n加\n油\n吧\n,\n學\n習\nFLutter\n!",
style: TextStyle(fontSize: 28),
),
),
),
);
}
}
效果:
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLiYWan5iMwITO2czNyI2NlFWOzAzYmBTN5IWYxYGZxYjZiZzY58CX0JXZ252bj91Ztl2Lc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.gif)
示例二 和SliverAppBar一起使用
import 'package:flutter/material.dart';
class NestedScrollViewDemo2 extends StatefulWidget {
@override
StatecreateState() {
return NestedScrollViewDemo2State();
}
}
class NestedScrollViewDemo2State extends State<NestedScrollViewDemo2> {
@override
Widget build(BuildContext context) {
return NestedScrollView(
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
return [SliverAppBar(
expandedHeight: 230.0,
pinned: true,
flexibleSpace: FlexibleSpaceBar(
centerTitle: true,
title: Text('戰狼'),
background: Image.network('https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=1396864856,3131267503&fm=26&gp=0.jpg',
fit: BoxFit.fitHeight,
),
),
)];
},
body: ListView.builder(itemBuilder: (BuildContext context,int index){return Container(
height: 80,
color: Colors.primaries[index % Colors.primaries.length],
alignment: Alignment.center,
child: Text('$index',
style: TextStyle(color: Colors.white, fontSize: 20),
),
);
},itemCount: 20,),
)
;
}
}
效果:
示例三-與TabBar和SliverPersistentHeader搭配使用
import 'dart:ui';
import 'package:flutter/material.dart';
class NestedScrollViewDemo3 extends StatefulWidget {
@override
StatecreateState() {
return NestedScrollViewDemo3State();
}
}
class NestedScrollViewDemo3State extends State<NestedScrollViewDemo3> {
TabController _controller;
@override
void initState() {
// TODO: implement initState
super.initState();
_controller = TabController(
length: 2,
vsync: ScrollableState(),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: NestedScrollView(
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
return [
SliverAppBar(
title: Text("碼上加油站"),
expandedHeight: 230.0,
pinned: true,
flexibleSpace: Padding(
padding: EdgeInsets.symmetric(vertical: 1),
child: PageView(
children: [
Container(
height: 230,
color: Colors.redAccent,
),
Container(
height: 230,
color: Colors.orange,
),
Container(
height: 230,
color: Colors.lightBlue,
)
],
),
),
),
SliverPersistentHeader(
pinned: true,
delegate: StickyTabBarDelegate(
child: TabBar(
labelStyle: TextStyle(
color: Colors.white,
fontSize: 14.0,
fontWeight: FontWeight.w600),
unselectedLabelStyle: TextStyle(
color: Colors.white,
fontSize: 14.0,
fontWeight: FontWeight.w600),
unselectedLabelColor: Colors.white60,
labelColor: Colors.white,
controller: _controller,
tabs: [
Tab(text: "熱門"),
Tab(text: "推薦"),
],
),
),
),
];
},
body: TabBarView(
controller: _controller,
children: [
ListView(
children: [
ListTile(title: Text("第一個tab")),
ListTile(title: Text("第一個tab")),
ListTile(title: Text("第一個tab"))
],
),
ListView(
children: [
ListTile(title: Text("第二個tab")),
ListTile(title: Text("第二個tab")),
ListTile(title: Text("第二個tab"))
],
)
],
),
),
);
}
}class StickyTabBarDelegate extends SliverPersistentHeaderDelegate {final TabBar child;
StickyTabBarDelegate({@required this.child});@overrideWidget build(
BuildContext context, double shrinkOffset, bool overlapsContent) {return Container(
color: Theme.of(context).backgroundColor,
child: this.child,
);
}@overridedouble get maxExtent => this.child.preferredSize.height;@overridedouble get minExtent => this.child.preferredSize.height;@overridebool shouldRebuild(SliverPersistentHeaderDelegate oldDelegate) {return true;
}
}
說明:delegate需要實作SliverPersistentHeaderDelegate 重寫其中的build方法實作子類容器, shouldRebuild方法中根據使用者自定義重繪條件傳回布爾值。
效果:
完
碼上加油站
一起來加油
長按掃碼關注
記得點個 贊 和 在看 哦!