I have a "NestedScrollView" that contains multiple "TabView" widgets and each one of those tabs has a list builder. The problem is that when i scroll through one list in a specific tab, the scroll position affects all the other lists in the other tabs.
Even if i do add "ScrollController" to each of the listview (in tabs), The listBuilder inside the tab scroll gets separated from the "NestedScrollView" here is an example code :
import 'package:flutter/material.dart';
void main() => runApp(
MaterialApp(
home: MyApp()
,
)
);
class MyApp extends StatefulWidget{
MyAppState createState() => MyAppState();
}
class MyAppState extends State<MyApp> with SingleTickerProviderStateMixin {
TabController tabController;
Widget _tabBarView;
@override
void initState() {
super.initState();
tabController = TabController(length: 2, vsync: this,);
_tabBarView = TabBarView(
children: [
DemoTab(),
DemoTab(),
]);
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: NestedScrollView(
controller: ScrollController(keepScrollOffset: true),
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
return <Widget>[
SliverList(
delegate: SliverChildListDelegate(
[
Container(height: 300, color: Colors.blue)
]
),
),
];
},
body: DefaultTabController(
length: 2,
child: Column(
children: <Widget>[
Expanded(
child: Container(
child: _tabBarView
),
),
],
),
)
),
);
}
}
class DemoTab extends StatefulWidget{
DemoTabState createState() => DemoTabState();
}
class DemoTabState extends State<DemoTab> with AutomaticKeepAliveClientMixin<DemoTab>{
@override
// TODO: implement wantKeepAlive
bool get wantKeepAlive => true;
@override
Widget build(BuildContext context) {
return ListView.builder(
key: UniqueKey(),
itemBuilder: (b, i) {
return Container(
height: 50,
color: Colors.green,
margin: EdgeInsets.only(bottom: 3),
child: Text(i.toString(),),
);
}, itemCount: 30,) ;
}
}
after 3 days i found this is the best solution to this problem ,but still need more improvement , cuz the sliver header expand and shrink too fast , you can improve code , and share us
import 'package:flutter/material.dart';
void main() => runApp(MaterialApp(
home: MyApp(),
));
class MyApp extends StatefulWidget {
MyAppState createState() => MyAppState();
}
class MyAppState extends State<MyApp> with SingleTickerProviderStateMixin {
TabController tabController;
Widget _tabBarView;
var scrollController = ScrollController();
@override
void initState() {
super.initState();
tabController = TabController(
length: 2,
vsync: this,
);
_tabBarView = TabBarView(children: [
DemoTab(parentController : scrollController),
DemoTab(parentController : scrollController),
]);
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: NestedScrollView(
controller: scrollController,
physics: ScrollPhysics(parent: PageScrollPhysics()),
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
return <Widget>[
SliverList(
delegate: SliverChildListDelegate(
[Container(height: 300, color: Colors.blue)]),
),
];
},
body: DefaultTabController(
length: 2,
child: Column(
children: <Widget>[
Container(
child: TabBar(labelColor: Colors.grey, tabs: [
Tab(
text: 'One',
),
Tab(
text: 'two',
)
]),
),
Expanded(
child: Container(child: _tabBarView),
),
],
),
)),
);
}
}
class DemoTab extends StatefulWidget {
DemoTab({
this.parentController
});
final ScrollController parentController;
DemoTabState createState() => DemoTabState();
}
class DemoTabState extends State<DemoTab>
with AutomaticKeepAliveClientMixin<DemoTab> {
@override
// TODO: implement wantKeepAlive
bool get wantKeepAlive => true;
ScrollController _scrollController;
ScrollPhysics ph;
@override
void initState() {
super.initState();
_scrollController = ScrollController();
_scrollController.addListener((){
var innerPos = _scrollController.position.pixels;
var maxOuterPos = widget.parentController.position.maxScrollExtent;
var currentOutPos = widget.parentController.position.pixels;
if(innerPos >= 0 && currentOutPos < maxOuterPos) {
//print("parent pos " + currentOutPos.toString() + "max parent pos " + maxOuterPos.toString());
widget.parentController.position.jumpTo(innerPos+currentOutPos);
}else{
var currenParentPos = innerPos + currentOutPos;
widget.parentController.position.jumpTo(currenParentPos);
}
});
widget.parentController.addListener((){
var currentOutPos = widget.parentController.position.pixels;
if(currentOutPos <= 0) {
_scrollController.position.jumpTo(0);
}
});
}
@override
Widget build(BuildContext context) {
return ListView.builder(
key: UniqueKey(),
controller: _scrollController,
itemBuilder: (b, i) {
return Container(
height: 50,
color: Colors.green,
margin: EdgeInsets.only(bottom: 3),
child: Text(
i.toString(),
),
);
},
itemCount: 30,
);
}
}