在嵌套滚动视图的外部主体上滚动侦听器



我正在尝试创建材料原生选项卡,因此当我们滚动页面时,appbar会折叠,但选项卡应该始终可见,我在flutter 中使用NestedScrollView实现了这一点

class HomeScreen extends StatefulWidget {
@override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> with SingleTickerProviderStateMixin {
TabController _tabController;
@override
void initState() {
super.initState();
_tabController = TabController(length: 2, vsync: this);
}
@override
void dispose() {
super.dispose();
_tabController.dispose();
}
@override
Widget build(BuildContext context) {
return NestedScrollView(
headerSliverBuilder: (BuildContext context, bool isBoxScrolled) {
return [
SliverAppBar(
title: Text("Scroller title"),
forceElevated: isBoxScrolled,
pinned: true,
floating: true,
bottom: TabBar(
tabs: [Tab(text: "tab1"), Tab(text: "tab2")],
controller: _tabController))
];
},
body: TabBarView(
children: [Page1(), Page1()],
controller: _tabController,
));
}
} 
class Page1 extends StatefulWidget {
@override
_Page1State createState() => _Page1State();
}
class _Page1State extends State<Page1> {
ScrollController _controller;
void _scrollListener(){
if(_controller.offset >= _controller.position.maxScrollExtent && !_controller.position.outOfRange){
print("reached the bottom");
}
}
@override
void initState() {
super.initState();
_controller = ScrollController();
_controller.addListener(_scrollListener);
}
@override
Widget build(BuildContext context) {
return ListView(
controller: _controller,
children: <Widget>[Text("data"), SizedBox(height: 2000.0)],
);
}
}

但当我尝试在我的一个tabBarview小部件中使用scrollController时,它会断开与appbar的联系并单独滚动。

解决方案是PrimaryScrollController

class HomeScreen extends StatefulWidget {
@override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> with SingleTickerProviderStateMixin {
TabController _tabController;
@override
void initState() {
super.initState();
_tabController = TabController(length: 2, vsync: this);
}
@override
void dispose() {
super.dispose();
_tabController.dispose();
}
@override
Widget build(BuildContext context) {
return NestedScrollView(
headerSliverBuilder: (BuildContext context, bool isBoxScrolled) {
return [
SliverAppBar(
title: Text("Scroller title"),
forceElevated: isBoxScrolled,
pinned: true,
floating: true,
bottom: TabBar(
tabs: [Tab(text: "tab1"), Tab(text: "tab2")],
controller: _tabController))
];
},
body: Builder(
builder: (BuildContext context) {
final innerScrollController = PrimaryScrollController.of(context);
// Use the innerScrollController to listen to the scrolling.
// This would be your controller for list. You can listen to this controller to know whether the list has reached maxScrollExtent and fetch data from API.
return TabBarView(
children: [
Page1(innerScrollController),
Page1(innerScrollController)
],
controller: _tabController,
);
},
),
);
}
}
class Page1 extends StatefulWidget {
final ScrollController _PrimaryScrollController;
Page1(this._PrimaryScrollController);
@override
_Page1State createState() => _Page1State();
}
class _Page1State extends State<Page1> {

void _scrollListener(){
if(this.widget._PrimaryScrollController.offset >= this.widget._PrimaryScrollController.position.maxScrollExtent && !this.widget._PrimaryScrollController.position.outOfRange){
print("reached the bottom");
}
}
@override
void initState() {
super.initState();
this.widget._PrimaryScrollController.addListener(_scrollListener);
}
@override
Widget build(BuildContext context) {
return ListView(
children: <Widget>[Text("data"), SizedBox(height: 2000.0)],
);
}
}

最新更新