1

How I can make the scroll of a list depending on another list scrolling for example :

class ConectLists extends StatefulWidget {
  const ConectLists({Key? key}) : super(key: key);

  @override
  State<ConectLists> createState() => _ConectListsState();
}

class _ConectListsState extends State<ConectLists> {
  ScrollController scrollConroller1 = ScrollController();
  ScrollController scrollConroller2 = ScrollController();
  @override
  void initState() {
    // TODO: implement initState
    super.initState();
  }

  @override
  void dispose() {
    // TODO: implement dispose
    scrollConroller1.dispose();
    scrollConroller2.dispose();

    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        children: [
          SizedBox(
            height: 8,
          ),
          Row(
            mainAxisAlignment: MainAxisAlignment.spaceEvenly,
            children: [
              Text('List 1'),
              Text('List 2'),
            ],
          ),
          SizedBox(
            height: 8,
          ),
          Container(
            color: Colors.black.withOpacity(0.5),
            width: double.infinity,
            height: 4,
          ),
          Expanded(
            child: Row(
              children: [
                Expanded(
                  flex: 1,
                  child: ListView.builder(
                    controller: scrollConroller1,
                    itemBuilder: (context, index) => Card(
                        elevation: 3,
                        child: SizedBox(
                            height: 40,
                            child:
                                Center(child: Text('First list item $index')))),
                    itemCount: 50,
                  ),
                ),
                Container(
                  color: Colors.black.withOpacity(0.5),
                  width: 4,
                  height: double.infinity,
                ),
                Expanded(
                  child: ListView.builder(
                    controller: scrollConroller2,
                    itemBuilder: (context, index) => Card(
                        elevation: 3,
                        child: SizedBox(
                            height: 40,
                            child: Center(
                                child: Text('Second list item $index')))),
                    itemCount: 25,
                  ),
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }
}

I need to make list 2 scroll when List1 scroll with controlling the speed of the list2 scrolling (different scroll speed) for example or reverse the direction for example..

Is there a lite way to do this in Fultter ?

enter image description here

3 Answers 3

2

You can easily achieve this by adding listeners to your ScrollController like so :

controller: scrollConroller1..addListener(() {
 scrollConroller2.animateTo(scrollConroller1.offset,
 curve: Curves.easeInOut,
 duration: const Duration(milliseconds: 450));
}),

Basically you listen on scroll changes and you assign ones' Offset to the other list. However, when the first list's length is larger than the second list,the second list will keep on bouncing at the bottom (on iOS devices). You could fix that by checking if the first list's offset is larger than the second list's maxScrollExtent :

controller: scrollConroller1..addListener(() {
 if (scrollConroller1.offset <= scrollConroller2.position.maxScrollExtent){
  scrollConroller2.animateTo(scrollConroller1.offset,
  curve: Curves.easeInOut,
  duration: const Duration(milliseconds: 450));
 }
}),
Sign up to request clarification or add additional context in comments.

4 Comments

Thank you very much this solution works fine. Is there a way less cost ? There is a clear time delay between the first and second scrolling ,is it possible to control the two lists with the same controller but with different behaviors for each list?
@JaafarMelhem try to put inside Duration another value. Ex: const Duration(microseconds: 1)
@JaafarMelhem or instead of using 'animateTo' you should try to use 'jumpTo' method.
Perhaps this is the only solution. I needed to make the second list scroll slower than the first, so when the first reaches the end, the second reaches the end in the same time, i.e. the second list scroll with the first, but slower by half and with a smooth movement that does not show jumps and time delays to interact with the first, thank you very much I appreciate your help
2

You could add a listener in your init state to make scrollConroller2 jump to the postion scrollConroller1 is at as below.

Credit to esentis for the fix when first list's offset is larger than the second list's maxScrollExtent :

@override
  void initState() {
    super.initState();
    //Your other code in init state
    scrollConroller1.addListener(() {
      if (scrollConroller1.offset <=
          scrollConroller2.position.maxScrollExtent) {
        setState(() {
          double value2 = scrollConroller1.offset;
          scrollConroller2.jumpTo(value2);
        });
      }
    });
  }

To scroll in reverse, you can set the listener instead to:

scrollConroller1.addListener(() {
      if (scrollConroller1.offset <=
          scrollConroller2.position.maxScrollExtent) {
        setState(() {
          double value2 = scrollConroller2.position.maxScrollExtent -
              scrollConroller1.offset;
          scrollConroller2.jumpTo(value2);
        });
      }
    });

Comments

1

To control list scroll while maintaining the scroll offset that will be based on height ratio, Therefore the jump offset will be

jumpPoss = (math.min(l1maxHeight, l2maxHeight) * scrollOffset) /
          math.max(l1maxHeight, l2maxHeight);
   late ScrollController scrollController1 = ScrollController()
    ..addListener(() {
      double scrollOffset = scrollController1.offset;

      final double l1maxHeight = scrollController1.position.maxScrollExtent;
      final double l2maxHeight = scrollController2.position.maxScrollExtent;

      double jumpPoss = (math.min(l1maxHeight, l2maxHeight) * scrollOffset) /
          math.max(l1maxHeight, l2maxHeight);
      scrollController2.jumpTo((jumpPoss));
    });

You can follow @Tonny Bawembye's answer if you need to stop scrolling on max limit.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.