Home > OS >  Both Listviews scrolling simultaneously within NestedScrollView
Both Listviews scrolling simultaneously within NestedScrollView

Time:10-09

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
  }

}
  • Related