50

What I needed:

I want to scroll a list by some index, how can i do that.

What I know:

scrollToIndex should start from n index, but how can we scroll to any index?

atline
  • 28,355
  • 16
  • 77
  • 113
Deepak Gehlot
  • 2,661
  • 5
  • 21
  • 25

7 Answers7

57

Unfortunately, ListView has no built-in approach to a scrollToIndex() function. You’ll have to develop your own way to measure to that element’s offset for animateTo() or jumpTo(), or you can search through these suggested solutions/plugins or from other posts like Flutter: Scrolling to a widget in ListView

(the general scrollToIndex issue is discussed at flutter/issues/12319 since 2017, but still with no current plans)


But there is a different kind of ListView that does support scrollToIndex (as mentioned by Slashbin):

You set it up exactly like ListView and works the same, except you now have access to a ItemScrollController that does:

  • jumpTo({index, alignment})
  • scrollTo({index, alignment, duration, curve})

Simplified example:

ItemScrollController _scrollController = ItemScrollController();

ScrollablePositionedList.builder(
  itemScrollController: _scrollController,
  itemCount: _myList.length,
  itemBuilder: (context, index) {
    return _myList[index];
  },
)

_scrollController.scrollTo(index: 150, duration: Duration(seconds: 1));

(note that this library is developed by Google but not by the core Flutter team.)

Pavel
  • 5,374
  • 4
  • 30
  • 55
TWL
  • 6,228
  • 29
  • 65
  • 1
    Fantastic answer. Though I noticed that when `index == item.length - 1`, the scrollController behaves funny. Perhaps it's because I used`BouncingScrollPhysics()` – Brendan Apr 20 '20 at 14:58
  • The downside of ScrollablePositionedList is that its incompatible with incremental scrolling requires (such as responding to arrow up/down keys), because its API does speak about offsets (even relative offsets). – user48956 Nov 06 '20 at 03:19
  • But I cannot set controller key for ScrollablePositionedList, it's not good if you want to do something more – Kien Vu May 12 '21 at 12:30
  • what about a ListView builder inside a streamBuilder. will this work? – RL Shyam Sep 26 '22 at 14:34
  • but the scrollable positioned list doest not have scrollcontroller like in listview builder which can be helpful to detect user scroll direction . – appdev Feb 10 '23 at 09:39
12

ScrollablePositionedList can be used for this. https://github.com/google/flutter.widgets/tree/master/packages/scrollable_positioned_list

Pub link - https://pub.dev/packages/scrollable_positioned_list

final ItemScrollController itemScrollController = ItemScrollController();
final ItemPositionsListener itemPositionListener = ItemPositionsListener.create();

ScrollablePositionedList.builder(
  itemCount: 500,
  itemBuilder: (context, index) => Text('Item $index'),
  itemScrollController: itemScrollController,
  itemPositionsListener: itemPositionListener,
);

One then can scroll to a particular item with:

itemScrollController.scrollTo(
  index: 150,
  duration: Duration(seconds: 2),
  curve: Curves.easeInOutCubic);
Pavel
  • 5,374
  • 4
  • 30
  • 55
Slashbin
  • 668
  • 5
  • 15
7

Use scroll_to_index lib, here scroll will be always performed to sixth position as its hardcoded below

dependencies:
    scroll_to_index: ^1.0.6

Code Snippet:

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final scrollDirection = Axis.vertical;

  AutoScrollController controller;
  List<List<int>> randomList;

  @override
  void initState() {
    super.initState();
    controller = AutoScrollController(
        viewportBoundaryGetter: () =>
            Rect.fromLTRB(0, 0, 0, MediaQuery.of(context).padding.bottom),
        axis: scrollDirection);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: ListView(
        scrollDirection: scrollDirection,
        controller: controller,
        children: <Widget>[
          ...List.generate(20, (index) {
            return AutoScrollTag(
              key: ValueKey(index),
              controller: controller,
              index: index,
              child: Container(
                height: 100,
                color: Colors.red,
                margin: EdgeInsets.all(10),
                child: Center(child: Text('index: $index')),
              ),
              highlightColor: Colors.black.withOpacity(0.1),
            );
          }),
        ],
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _scrollToIndex,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
  // Scroll listview to the sixth item of list, scrollling is dependent on this number
  Future _scrollToIndex() async {
    await controller.scrollToIndex(6, preferPosition: AutoScrollPosition.begin);
  }
}

Output:

enter image description here

Jitesh Mohite
  • 31,138
  • 12
  • 157
  • 147
3

You can use the flutter_scrollview_observer lib to implement your desired functionality without invasivity

Create and use instance of ScrollController normally.

ScrollController scrollController = ScrollController();

ListView _buildListView() {
  return ListView.separated(
    controller: scrollController,
    ...
  );
}

Create an instance of ListObserverController pass it to ListViewObserver

ListObserverController observerController = ListObserverController(controller: scrollController);

ListViewObserver(
  controller: observerController,
  child: _buildListView(),
  ...
)

Now you can scroll to the specified index position

// Jump to the specified index position without animation.
observerController.jumpTo(index: 1)

// Jump to the specified index position with animation.
observerController.animateTo(
  index: 1,
  duration: const Duration(milliseconds: 250),
  curve: Curves.ease,
);
LinXunFeng
  • 41
  • 3
  • Thanks a lot for your package @LinXunFeng, it works like a charm ;) I'm using it with nb_utils AnimatedListView , and works fine, thanks bro' – RoyalCoder Dec 07 '22 at 18:50
2

It's simple to scroll to preferred index if you know listview item size like:

var index = 15;
var widthOfItem =
176; //in dp. width needed for horizontallistView;
var heightOfItem =
200; //in dp. height need for vertical listView;
listViewScrollController.jumpTo(index * widthOfItem.toDouble());

or

listViewScrollController.animateTo(
index * widthOfItem.toDouble(),
duration: Duration(milliseconds: 500),
curve: Curves.ease);
Hussnain Haidar
  • 2,200
  • 19
  • 30
1

Found a gist and its working gist url is https://gist.github.com/debuggerx01/b8ef756ee02b3eb82ec3702f14ba94e6

this gist is using a package which is calculation rect size. https://pub.dartlang.org/packages/rect_getter

Deepak Gehlot
  • 2,661
  • 5
  • 21
  • 25
0

You can scroll into position by calculating your item position.

int itemCount = 5; // your items count
ScrollController scrollController = ScrollController();
int index = 2; // your item index to scroll

scrollController.jumpTo(
   scrollController.position.maxScrollExtent/ 
     (itemCount-1) * index
);

This will scroll you to some way around item, then you can have the best place for yourself by index some offset

mahdi shahbazi
  • 1,882
  • 10
  • 19