Scroll synchronisation for multiple scrollable widgets

276

That's because every time you call jumpTo method it call the first one, and the first one call the second one and you will have an infinity loop.

The solution is that you create your own ScrollController with it owns method to jump to another position without notification.

This is the custom scroll controller that you can create:

            class CustomScrollController extends ScrollController {
              CustomScrollController({
                double initialScrollOffset = 0.0,
                keepScrollOffset = true,
                debugLabel,
              }) : super(
                        initialScrollOffset: initialScrollOffset,
                        keepScrollOffset: keepScrollOffset,
                        debugLabel: debugLabel);

              @override
              _UnboundedScrollPosition createScrollPosition(
                ScrollPhysics physics,
                ScrollContext context,
                ScrollPosition oldPosition,
              ) {
                return _UnboundedScrollPosition(
                  physics: physics,
                  context: context,
                  oldPosition: oldPosition,
                  initialPixels: initialScrollOffset,
                );
              }

              void jumpToWithoutGoingIdleAndKeepingBallistic(double value) {
                assert(positions.isNotEmpty, 'ScrollController not attached.');
                for (_UnboundedScrollPosition position
                    in new List<ScrollPosition>.from(positions))
                  position.jumpToWithoutGoingIdleAndKeepingBallistic(value);
              }
            }

            class _UnboundedScrollPosition extends ScrollPositionWithSingleContext {
              _UnboundedScrollPosition({
                ScrollPhysics physics,
                ScrollContext context,
                ScrollPosition oldPosition,
                double initialPixels,
              }) : super(
                      physics: physics,
                      context: context,
                      oldPosition: oldPosition,
                      initialPixels: initialPixels,
                    );

              /// There is a feedback-loop between aboveController and belowController. When one of them is
              /// being used, it controls the other. However if they get out of sync, for timing reasons,
              /// the controlled one with try to control the other, and the jump will stop the real controller.
              /// For this reason, we can't let one stop the other (idle and ballistics) in this situation.
              void jumpToWithoutGoingIdleAndKeepingBallistic(double value) {
                if (pixels != value) {
                  forcePixels(value);
                }
              }
            }

And just call to jumpToWithoutGoingIdleAndKeepingBallistic instead of jumpTo .

A working sample here:

https://gist.github.com/diegoveloper/75e55ca2e4cee03bff41a26254d6fcf6

Result

enter image description here

Share:
276
siva kumar
Author by

siva kumar

Updated on December 10, 2022

Comments

  • siva kumar
    siva kumar over 1 year

    Scroll synchronisation for multiple scrollable widgets:

    I want to scroll second list if scroll first list and scroll first list if scroll second list.It is going to Recursive can anyone help for this, thanks in advance.

    import 'package:flutter/cupertino.dart';
    class MyHomePage extends StatefulWidget {
     @override
     _MyHomePageState createState() => _MyHomePageState();
    }
    
    class _MyHomePageState extends State<MyHomePage> {
      ScrollController firstScroll = ScrollController();
      ScrollController secondScrollController = ScrollController();
    
      @override
      void initState() {
         super.initState();
         firstScroll.addListener(() {
        //THIS IS called when scroll is triggered,
            secondScrollController
               .jumpTo(firstScroll.offset); // THIS will sync the scroll;
         });
    
     secondScrollController.addListener(() {
        //THIS IS called when scroll is triggered,
            firstScroll
               .jumpTo(secondScrollController.offset); // THIS will sync the scroll;
         });
       }
    
       @override
       Widget build(BuildContext context) {
         return Container(
            child: Column(
              children: <Widget>[
                SingleChildScrollView(
                 // this is the first scroll
                    scrollDirection: Axis.horizontal,
                    controller: firstScroll, // THIS IS THE FIRST SCROLL CONTROLLER
                    child: Container(
                       //TODO: add your content here here
                    ),
                ),
                SingleChildScrollView(
                   scrollDirection: Axis.horizontal,
                   controller: secondScrollController,
                   // HERE YOU SET THE SECOND CONTROLLER
                   child: Container(
                      //TODO: add your content here
                   ),
                 )
            ],
        ),
     );
    }
    }
    
  • siva kumar
    siva kumar about 5 years
    Thanks for the solution but If I tried like this the bouncing effect is missing and the list goes even for empty space.(i.e.., more than the extent) added image in Question.
  • diegoveloper
    diegoveloper about 5 years
    shrinkWrap: true , remove the bouncing effect of your List, if you remove that value you could have some issues in your layout, try using Slivers
  • siva kumar
    siva kumar about 5 years
    It is an single child scroll controller, and we want bouncing effect as per the requirement
  • diegoveloper
    diegoveloper about 5 years
  • siva kumar
    siva kumar about 5 years
    Not working dude. bouncing effect is not coming and scroll is not free. it is Jerking.
  • diegoveloper
    diegoveloper about 5 years
    Did you run my sample? I modified the scroll controller code
  • siva kumar
    siva kumar about 5 years