Infinite List in Flutter Application
Asked Answered
S

2

9

I am migrating my application from android to flutter and till now I have used ListView in a flutter. my question is, is there any specialized technique to handle a large amount of data in the flutter? for reference, you can look at android RecyclerView. it handles in-memory views and recycles its runtime. so how to achieve functionality like RecyclerView in Flutter? or it's not necessary for the flutter?

Specialize answered 2/11, 2018 at 8:13 Comment(3)
use ListView.builderSwett
Flutter ListView is analog of ListView in android. ListView.builder is analog of RecyclerView.Spasm
The Write Your First Flutter App uses the ListView.builder as an example but you can get more information on Working with long lists herePolemist
P
33

The easiest way is to use a ListView.builder without specifying the itemCount parameter.

Here is the simplest example:

import 'package:flutter/material.dart';

void main() => runApp(new MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      home: new MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => new _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text("Infinite List"),
      ),
      body: ListView.builder(
        itemBuilder: (context, index) {
          return Text("$index");
        },
      ),
    );
  }
}

Later, you can enhance this by fetching real data. You could show a 'CircularProgressIndicator' in the last item of the list while waiting for the new data.

  body: ListView.builder(
    itemBuilder: (context, index) {
      if (index < data.length) {
        // Show your info
        return Text("$index");
      } else {
        getMoreData();
        return Center(child: CircularProgressIndicator());
      }
    },
    itemCount: data.length + 1,
  ),

You can see that we trick the list by adding an index, and calling for more data when displaying that final index.

getMoreData() would include a call to setState() to force a rebuild and to take into account the new data.

Partridge answered 2/11, 2018 at 10:10 Comment(1)
I have added some explanation for an infinite list with real data.Partridge
S
4

Below is a simple infinite list widget based on chemamolins's answer. It accepts an itemBuilder to build the current item and onRequest callback to request more data when the user scrolls to the bottom.

import 'package:flutter/material.dart';

typedef Future<List<T>> RequestFn<T>(int nextIndex);
typedef Widget ItemBuilder<T>(BuildContext context, T item, int index);

class InifiniteList<T> extends StatefulWidget {
  final RequestFn<T> onRequest;
  final ItemBuilder<T> itemBuilder;

  const InifiniteList(
      {Key? key, required this.onRequest, required this.itemBuilder})
      : super(key: key);

  @override
  _InifiniteListState<T> createState() => _InifiniteListState<T>();
}

class _InifiniteListState<T> extends State<InifiniteList<T>> {
  List<T> items = [];
  bool end = false;

  _getMoreItems() async {
    final moreItems = await widget.onRequest(items.length);
    if (!mounted) return;

    if (moreItems.isEmpty) {
      setState(() => end = true);
      return;
    }
    setState(() => items = [...items, ...moreItems]);
  }

  @override
  Widget build(BuildContext context) {
    return ListView.builder(
      itemBuilder: (context, index) {
        if (index < items.length) {
          return widget.itemBuilder(context, items[index], index);
        } else if (index == items.length && end) {
          return const Center(child: Text('End of list'));
        } else {
          _getMoreItems();
          return const SizedBox(
            height: 80,
            child: Center(child: CircularProgressIndicator()),
          );
        }
      },
      itemCount: items.length + 1,
    );
  }
}

Usage

child: InifiniteList<String>(
  onRequest: requestItems,
  itemBuilder: (context, item, index) => Container(
    padding: const EdgeInsets.all(30),
    color: index % 2 == 0 ? Colors.purple.shade100 : Colors.lime.shade100,
    child: Text(item, style: Theme.of(context).textTheme.headline6),
  ),
),
// normally this is the place where you request the next batch of items
// on the network.
Future<List<String>> requestItems(int nextIndex) {
  const pageSize = 15;
  var result = List<String>.generate(pageSize, (i) => "Item: ${nextIndex + i + 1}");
  return Future<List<String>>.delayed(
    const Duration(milliseconds: 500),
    () => result,
  );
}

Live Demo

Satsuma answered 27/8, 2021 at 17:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.