可以在其内部嵌套其他滚动视图的滚动视图,其滚动位置是固有链接的。
在普通的[ScrollView]中, 如果有一个Sliver组件容纳了一个[TabBarView],它沿相反的方向滚动(例如,允许用户在标签所代表的页面之间水平滑动,而列表则垂直滚动),则该[TabBarView]内部的任何列表都不会相互作用 与外部[ScrollView]。 例如,浏览内部列表以滚动到顶部不会导致外部[ScrollView]中的[SliverAppBar]折叠以展开。
定义
const NestedScrollView({
Key key,
this.controller, //滚动控制器,可以监听滚到的位置,设置滚动的位置等
this.scrollDirection = Axis.vertical, //滚动方向,分为垂直和水平方向。
this.reverse = false, //表示反转滚动方向,并不是有垂直转为水平,而是垂直方向滚动时,默认向下滚动,
this.physics, //表示可滚动组件的物理滚动特性
@required this.headerSliverBuilder,
@required this.body,
this.dragStartBehavior = DragStartBehavior.start,
this.floatHeaderSlivers = false,
this.clipBehavior = Clip.hardEdge,
this.restorationId,
})
示例:滚动隐藏AppBar
import 'package:flutter/material.dart';
class ScrollDemo3 extends StatefulWidget {
@override
_ScrollDemo3State createState() => _ScrollDemo3State();
}
class _ScrollDemo3State extends State<ScrollDemo3> {
@override
Widget build(BuildContext context) {
return NestedScrollView(
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
return [
SliverAppBar(
title: Text('hello flutter'),
),
];
},
body: Container(
child: ListView.builder(
itemCount: 20,
itemBuilder: (context, 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)),
);
},
),
),
);
}
}
示例:SliverAppBar 展开折叠
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
return [
SliverAppBar(
expandedHeight: 230.0,
// title: Text('hello flutter'),
pinned: true,
flexibleSpace: FlexibleSpaceBar(
title: Text('复仇者联盟'),
background: Image.network(
'http://img.haote.com/upload/20180918/2018091815372344164.jpg',
fit: BoxFit.fill,
),
),
),
];
},
示例:与TabBar配合使用
import 'package:flutter/material.dart';
class ScrollDemo3 extends StatefulWidget {
@override
_ScrollDemo3State createState() => _ScrollDemo3State();
}
class _ScrollDemo3State extends State<ScrollDemo3> with SingleTickerProviderStateMixin {
TabController _tabController; //tab控制器
@override
void initState() {
super.initState();
_tabController = TabController(length: 2, vsync: this);
}
@override
Widget build(BuildContext context) {
return NestedScrollView(
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
return [
SliverAppBar(
expandedHeight: 230.0,
pinned: true,
flexibleSpace: FlexibleSpaceBar(
title: Text('复仇者联盟'),
background: Image.network(
'http://img.haote.com/upload/20180918/2018091815372344164.jpg',
fit: BoxFit.fill,
),
),
),
SliverList(
delegate: SliverChildListDelegate([
Text('fsdfs'),
]),
),
SliverPersistentHeader(
pinned: true,
// floating: true,
delegate: StickySliverPersistentHeader(
child: TabBar(
controller: _tabController,
tabs: [
Tab(text: '咨询'),
Tab(text: '技术'),
],
),
),
),
];
},
body: Container(
child: TabBarView(
controller: _tabController,
children: [
ListView.builder(
itemCount: 20,
itemBuilder: (context, 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)),
);
},
),
ListView.builder(
itemCount: 20,
itemBuilder: (context, 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)),
);
},
),
],
),
),
);
}
}
class StickySliverPersistentHeader extends SliverPersistentHeaderDelegate {
final child;
StickySliverPersistentHeader({@required this.child});
@override
Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) {
return Container(
color: Colors.green,
child: this.child,
);
}
@override
double get minExtent => this.child.preferredSize.height;
double get maxExtent => this.child.preferredSize.height;
@override
bool shouldRebuild(covariant SliverPersistentHeaderDelegate oldDelegate) {
return true;
}
}