indexed_list_view 1.0.8

  • Readme
  • Changelog
  • Example
  • Installing
  • 95

pub package

indexed_list_view #

Similar to a ListView, but lets you programmatically jump to any item, by index. The index jump happens instantly, no matter if you have millions of items.

Limitation: The list is always infinite both to positive and negative indexes. In other words, it can be scrolled indefinitely both to the top and to the bottom.

You can define index bounds by giving it a minItemCount and maxItemCount, but this will not prevent the list from scrolling indefinitely. When showing items out of the index bounds, or when your itemBuilder returns null, it will ask the emptyItemBuilder to create an "empty" item to be displayed instead. As default, this will return empty containers.

Usage #

Import the package #

Add indexed_list_view as a dependency in your pubspec.yaml file, and then import it:

import 'package:indexed_list_view/indexed_list_view.dart';

Use the package #

First, create an indexed scroll controller:

var controller = IndexedScrollController();

Optionally, you may setup an initial index and/or initial scroll offset:

var controller = IndexedScrollController(
    initialIndex: 75,
    initialScrollOffset : 30.0);    

Then, create the indexed list view, and pass it the controller:

    controller: controller, 
    itemBuilder: itemBuilder);

There is also the separated constructor, same as ListView.separated:

    controller: controller, 
    itemBuilder: itemBuilder,
    separatorBuilder: separatorBuilder);

To jump, use the controller methods like jumpToIndex :


Details #

The IndexedScrollController has not only an offset in pixels, but also an origin-index that indicates which item is considered to be at the offset position 0.0.

So there are two ways for you to move the list programmatically: You can change only the offset, or else change the originIndex and the offset at the same time.

To change the originIndex you make an "index jump". This jump is cheap, since it doesn't need to build all widgets between the old and new positions. It will just change the origin.

If you want to move the list programmatically you must create a scroll controller of type IndexedScrollController and pass it in the list constructor. However, if all you need is an infinite list without jumps, then there is no need to even create a controller.

You move the list programmatically by calling the controller methods.

Controller Methods #

  1. jumpToIndex(index)

    The is the most common method for you to use. It jumps the origin-index to the given index, and the scroll-position to 0.0.

  2. jumpToIndexAndOffset(index, offset)

    Jumps the origin-index to the given index, and the scroll-position to offset, without animation.

  3. animateToIndex(index)

    If the current origin-index is already the same as the given index, animates the position from its current value to the offset position relative to the origin-index.

    However, if the current origin-index is different from the given index, this will jump to the new index, without any animation. In general, there are never animations when the index changes.

  4. animateToIndexAndOffset(index, offset)

    Same as animateToIndex() but also lets you specify the new offset.

  5. jumpTo(offset)

    Goes to origin-index "0", and then jumps the scroll position from its current value to the given offset, without animation.

  6. animateTo(offset)

    If the current origin-index is already "0", animates the position from its current value to the offset position.

    However, if the current origin-index is different from "0", this will jump to index "0" and the given offset, without any animation. In general, there are never animations when the index changes.

  7. jumpToWithSameOriginIndex(offset)

    Jumps the offset, relative to the current origin-index.

  8. animateToWithSameOriginIndex(offset)

    Animates the offset, relative to the current origin-index.

  9. jumpToRelative(offset)

    Jumps the offset, adding or subtracting from the current offset. It keeps the same origin-index.

  10. animateToRelative(offset)

    Animates the offset, adding or subtracting from the current offset. It keeps the same origin-index.

Don't forget to check the example tab. It shows an infinite list of items of different heights, and you may tap buttons to run some of the methods explained above.

Hopefully this widget will become obsolete when Flutter's original ListView allows for negative indexes and for indexed jumps. See:

This package got some ideas from Collin Jackson's code in StackOverflow, and uses lots of code from Simon Lightfoot's infinite_listview.

The Flutter packages I've authored:

Marcelo Glasberg:

[0.0.1] - 2018/08/14 #

  • Infinite list (both up and down).
  • Jump to index.

[0.0.2] - 2018/08/14 #

  • Small fixes.
  • Initial animateToIndex.

[0.0.3] - 2018/08/15 #

  • Small fix.

[0.0.4] - 2018/09/12 #

  • Removed unnecessary code.

[0.0.5] - 2019/02/22 #

  • Fixed dart version.

[1.0.0] - 2019/08/06 #

  • New design based on infinite_list_view.

[1.0.5] - 2019/08/28 #

  • Lets you define NeverScrollableScrollPhysics.

[1.0.6] - 2019/08/28 #

  • MinItemCount and maxItemCount.

[1.0.8] - 2019/08/30 #

  • Fixed PageStorageKey.


import 'dart:math';

import 'package:flutter/material.dart';
import 'package:indexed_list_view/indexed_list_view.dart';

void main() => runApp(MaterialApp(home: HomePage()));

class HomePage extends StatelessWidget {
  static IndexedScrollController controller = IndexedScrollController(initialIndex: 75);

  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('IndexedListView'),
        backgroundColor: Colors.grey[800],
      body: Column(
        children: [
            child: IndexedListView.builder(
              controller: controller,
              itemBuilder: itemBuilder(),
          Container(height: 3.0, color:,
            color: Colors.grey[800],
            child: Column(
              children: [
                // ---
                  mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                  children: [
                    button("jumpToIndex(-42)", () => controller.jumpToIndex(-42)),
                    button("jumpToIndex(750000)", () => controller.jumpToIndex(750000)),
                // ---
                  mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                  children: [
                    button("animateToIndex(-42)", () => controller.animateToIndex(-42)),
                    button("animateToIndex(750000)", () => controller.animateToIndex(750000)),
                // ---
                  mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                  children: [
                    button("jumpTo(-15)", () => controller.jumpTo(-15)),
                    button("jumpTo(0)", () => controller.jumpTo(0)),
                    button("jumpTo(50)", () => controller.jumpTo(50)),
                // ---
                  mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                  children: [
                    button("animateTo(-30)", () => controller.animateTo(-30)),
                    button("animateTo(50)", () => controller.animateTo(50)),
                // ---
                  mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                  children: [
                    button("jumpToRelative(-250)", () => controller.jumpToRelative(-250)),
                    button("jumpToRelative(40)", () => controller.jumpToRelative(40)),
                // ---
                  mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                  children: [
                    button("animateToRelative(-250)", () => controller.animateToRelative(-250)),
                    button("animateToRelative(40)", () => controller.animateToRelative(40)),

  Widget button(String text, VoidCallback function) => Padding(
        padding: const EdgeInsets.all(4.0),
        child: RawMaterialButton(
          materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
          padding: const EdgeInsets.all(10.0),
          constraints: const BoxConstraints(minWidth: 88.0, minHeight: 30.0),
          child: Text(text, style: TextStyle(fontSize: 12)),
          onPressed: function,

  Function itemBuilder() {
    final List<double> heights =
        new List<double>.generate(527, (i) => Random().nextInt(200).toDouble() + 30.0);

    return (BuildContext context, int index) {
      return Card(
        child: Container(
          height: heights[index % 527],
          color: (index == 0) ? :,
          child: Center(child: Text('ITEM $index')),

Use this package as a library

1. Depend on it

Add this to your package's pubspec.yaml file:

  indexed_list_view: ^1.0.8

2. Install it

You can install packages from the command line:

with Flutter:

$ flutter pub get

Alternatively, your editor might support flutter pub get. Check the docs for your editor to learn more.

3. Import it

Now in your Dart code, you can use:

import 'package:indexed_list_view/indexed_list_view.dart';
Describes how popular the package is relative to other packages. [more]
Code health derived from static analysis. [more]
Reflects how tidy and up-to-date the package is. [more]
Weighted score of the above. [more]
Learn more about scoring.

We analyzed this package on Feb 27, 2020, and provided a score, details, and suggestions below. Analysis was completed with status completed using:

  • Dart: 2.7.1
  • pana: 0.13.5
  • Flutter: 1.12.13+hotfix.8

Health suggestions

Format lib/indexed_list_view.dart.

Run flutter format to format lib/indexed_list_view.dart.


Package Constraint Resolved Available
Direct dependencies
Dart SDK >=2.0.0 <3.0.0
flutter 0.0.0
Transitive dependencies
collection 1.14.11 1.14.12
meta 1.1.8
sky_engine 0.0.99
typed_data 1.1.6
vector_math 2.0.8
Dev dependencies