skip to Main Content

I have an image which has large width which has horizontal scroll. There is a list below that. The image is fixed. I want to scroll the image horizontally when scrolling the list vertically. How to connect these two widgets in flutter? Is it possible to do this in flutter?

The use case is list has many items. When we scroll to a particular item we need to scroll the image to a particular point. Thanks.

2

Answers


  1. Wrapping your- ListView.builder with Expanded Widget & setting mainAxisSize: MainAxisSize.min, of Column Widget.

    E.x Code .

     body: Column(
            mainAxisSize: MainAxisSize.min,
            children: <Widget>[
              Text(
                'Headline',
                style: TextStyle(fontSize: 18),
              ),
              Expanded(
                child: ListView.builder(
                  shrinkWrap: true,
                  scrollDirection: Axis.horizontal,
                  itemCount: 15,
                  itemBuilder: (BuildContext context, int index) => Card(
                        child: Center(child: Text('Dummy Card Text')),
                      ),
                ),
              ),
              Text(
                'Demo Headline 2',
                style: TextStyle(fontSize: 18),
              ),
              Expanded(
                child: ListView.builder(
                  shrinkWrap: true,
                  itemBuilder: (ctx,int){
                    return Card(
                      child: ListTile(
                          title: Text('Motivation $int'),
                          subtitle: Text('this is a description of the motivation')),
                    );
                  },
                ),
              ),
            ],
          ),
    

    enter image description here

    Login or Signup to reply.
  2. You could wrap the image that you want to scroll horizontally in a SingleChildScrollView, and will most likely use a ListView for your vertically scrolling list. Both of these widgets have a controller property, that’s where you can connect the scroll position of the two.

    If you want to control the scrolling position of your image based on the scrolling position of your list, you need to read the offset of the controller of your list every time it changes (when the user scrolls the list). Then you need to correct this value with the ratio of the physical length of the two scrolling widgets. You can get this value by calling controller.position.maxScrollExtent. This step is needed because the offset of the scroll controllers is an absolute value. Then call the jumpTo() method of the controller of the horizontally scrolling image with the value you calculated in the previous step.

    Below is an example where the position of the horizontally scrolling bar is kept in sync with the scroll position of the ListView. I used a Container instead of a wide image, but the idea is the same. The bar will stay in sync with the list regardless of their relative size. You can test it by changing the number of the list tiles or the width of the Container.

    import 'package:flutter/material.dart';
    
    class SynchronizedScroller extends StatefulWidget {
      const SynchronizedScroller({super.key});
    
      @override
      State<SynchronizedScroller> createState() => _SynchronizedScrollerState();
    }
    
    class _SynchronizedScrollerState extends State<SynchronizedScroller> {
      final horizontalController = ScrollController();
      final verticalController = ScrollController();
    
      double? controllerLengthRatio;
    
      @override
      void initState() {
        verticalController.addListener(() {
          controllerLengthRatio ??= horizontalController.position.maxScrollExtent /
              verticalController.position.maxScrollExtent;
          setState(() {
            horizontalController
                .jumpTo(verticalController.offset * controllerLengthRatio!);
          });
        });
        super.initState();
      }
    
      @override
      void dispose() {
        horizontalController.dispose();
        verticalController.dispose();
        super.dispose();
      }
    
      @override
      Widget build(BuildContext context) {
        List<ListTile> createVerticalList() {
          final listTiles = <ListTile>[];
          for (var i = 0; i < 50; i++) {
            listTiles.add(
              ListTile(
                title: Text(
                  'Listtile #${i.toString()}',
                  style: Theme.of(context).textTheme.headlineMedium,
                ),
              ),
            );
          }
          return listTiles;
        }
    
        return Scaffold(
          appBar: AppBar(),
          body: Column(
            mainAxisSize: MainAxisSize.min,
            children: [
              SingleChildScrollView(
                controller: horizontalController,
                scrollDirection: Axis.horizontal,
                child: Container(
                  height: 100,
                  width: 1500,
                  decoration: const BoxDecoration(
                      gradient: LinearGradient(colors: [
                    Colors.red,
                    Colors.green,
                    Colors.white,
                    Colors.blue,
                    Colors.amber,
                    Colors.cyan,
                    Colors.black,
                    Colors.brown,
                  ])),
                ),
              ),
              Flexible(
                child: ListView(
                  controller: verticalController,
                  shrinkWrap: true,
                  children: createVerticalList(),
                ),
              )
            ],
          ),
        );
      }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search