I am facing a problem of 2 listViews scrolled at the same time :
DefaultTabController(
length: 2,
child: NestedScrollView
(
headerSliverBuilder: (context, innerBoxIsScrolled)
{
return
[
SliverAppBar(
title: Text('HOME', style: Theme.of(context).textTheme.headline5,),
floating: true,
pinned: false,
snap: true,
titleSpacing: 0.1,
bottom: TabBar(
isScrollable: true,
indicatorSize: TabBarIndicatorSize.label,
labelPadding: EdgeInsets.symmetric(horizontal: 60),
controller: tabController,
tabs:
[
Tab(child: Text('Tab 1', style: Theme.of(context).textTheme.headline6,)),
Tab(child: Text('Tab 2', style: Theme.of(context).textTheme.headline6)),
],
),
),
];
}, //header sliver builder
body: TabBarView(
controller: tabController,
children:
[
ListViews1, //ListView.builder
ListViews2 //ListView.builder
],
),
)
),
The tabbar controller listens to change when swiped or clicked on the tab. Indexed are being returned correctly. 0 for 1st tab and 1 for 2nd tab
tabController = TabController(length: 2, vsync: this);
tabController.addListener(_handleTabSelection);
void _handleTabSelection() {
if(!tabController.indexIsChanging)
{
log('CALLED : ${tabController.index}');
}
}
Both classes are kept alive so that the scroll position shouldn't get lost:
class _ListView1State extends State<ListView1> with AutomaticKeepAliveClientMixin<ListView1>{
@override
bool get wantKeepAlive => true;
class _ListView2State extends State<ListView2> with AutomaticKeepAliveClientMixin<ListView2>{
@override
bool get wantKeepAlive => true;
PROBLEM : When i scroll the first list, the 2nd list also gets scrolled automatically and vice versa. What is the problem here ?
CodePudding user response:
Both of them are being kept alive and both of them read the controller from the primary controller (which is created by NestedScrollView) when controller = null
and primary = true
(which seems the case). I dont' have a way to test it but here is what I could do:
simply create a ScrollController in each state and check if they preserve their value independently
class _ListView1State extends State<ListView1> with AutomaticKeepAliveClientMixin<ListView1>{
late final ScrollController _scrollController;
@override
void initState() {
_scrollController = ScrollController();
super.initState();
}
@override
void dispose() {
_scrollcontroller.dispose();
super.dispose();
}
@override
bool get wantKeepAlive => true;
@override
Widget build(BuildContext context) {
return .....
//// pass the controller to the scroll widget you use
}
}
Repeat with _ListView2State and try it, now they should preserve their own state in the scrolling too
EDIT
What about reading the tabController and switching to a scrollController when is not being displayed
class _ListView1State extends State<ListView1> with AutomaticKeepAliveClientMixin<ListView1>{
ScrollController? _scrollController;
double? _offset;
TabController tabController;
///And repeat with index tabController.index != 1 for ListView2
void setController() {
if (tabController.index != 0 && scrollController == null) {
_offset = PrimaryScrollController.of(context).controller.offset;
scrollController = ScrollController(initialScrollOffset: _offset ?? 0);
setState(() {});
} else if (tabController.index == 0 && scrollController != null) {
final primary = PrimaryScrollController.of(context).controller;
if (_offset != null && primary.offset != _offset) primary .jumpTo(_offset);
setState(() {
_offset = scrollController.offset;
scrollController = null;
});
}
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
final _tabController = DefaultTabController.of(context);
if (tabController != null &&_tabController != tabController) {
tabController.removeListener(setController);
}
tabController = _tabController;
tabController.addListener(setController);
}
@override
void dispose() {
_scrollcontroller?.dispose();
tabController.removeListener(setController);
super.dispose();
}
@override
bool get wantKeepAlive => true;
@override
Widget build(BuildContext context) {
return .....
//// pass the controller to the scroll widget you use
}
}