2

I need to develop a list of potentially infinite items loaded from a server. When the user arrives to the end of the list other items must be loaded.
I am looking for the web to understand what is the best practice to do that in flutter.

This is what I found:

ListView.builder with a ScrollController that load new items when it comes to the end, with this code:

if (_controller.position.pixels == _controller.position.maxScrollExtent) {
  // load other items
}

The problem of this approach is I have to save the last page I loaded from the server to not load same items again.

I also found StreamBuilder, FutureBuilder and PaginatedDataTable, but I am not sure if they are the correct widgets to manage infinite list.
What is the best approach of this problem?

Giacomo M
  • 4,450
  • 7
  • 28
  • 57

1 Answers1

2

I have a very interesting technique to show you how you can achieve your desired result in a best possible way.

Disclaimers

  • I have used my data set to show how the list being appended with the new data, not the duplicate one
  • I have demonstrated the data append when you click on a button, to see the upcoming data at the bottom, you can use your scrollController. You can do the operation in _loadMore()

Idea

  • We maintain two lists, one is original, and one which keep track of adding new data. Names are originalList and items.
  • We use two variables, one is perPageItems to show case the items based upon our will and presentItems to maintain how much data loaded till now. It starts with 0
  • While creating an item, we copy it to the items as well

Follow the code, and I have added most of the comments for your ease. Hope you get the end result

class _MyHomePageState extends State<MyHomePage> {
  int perPageItems  = 15;
  int presentItems = 0;
  
  List<String> items = List<String>();
  List<String> originalItems = new List.generate(100, (index) => 'Hello $index');

  @override
  void initState() {
    super.initState();
    
    // copying the data source to the other list
    items.addAll(originalItems.getRange(presentItems, presentItems + perPageItems));
    // updating the present Items now, since it has perPageItems now in the page
    presentItems = presentItems + perPageItems;
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      body: new Scrollbar(
        child: new ListView.builder(
          itemBuilder: (context, index) {
            // to check whether we have reached to the
            // the last page, which is the last item
            // as per the page count which is 15
            return (index == items.length ) ?
              Container(
                  color: Colors.greenAccent,
                  child: FlatButton(
                      child: Text("Load More"),
                      onPressed: () => _loadMore(),
                  ),
              ) : ListTile(
                  title: Text('${items[index]}'),
              );
          },
          // Here in the code itemCount if present i.e., 
          // no of items loaded is lessthan or equal to total no of items 
          // in original list then we return +1 so we can add LoadMore 
          // else we return the size of the list
          itemCount: (presentItems <= originalItems.length) ? items.length + 1 : items.length
        )
      ),
    );
  }

  // Here in the code if present + perPage will become new final no of 
  // list to be loaded is greater then out complete original list 
  // length then we pass originalItems.length in the getRange else we 
  // pass present + perPage in getRange
  void _loadMore() {
    setState(() {
        if((presentItems + perPageItems) > originalItems.length) {
            items.addAll(
                originalItems.getRange(presentItems, originalItems.length));
        } else {
            items.addAll(
                originalItems.getRange(presentItems, presentItems + perPageItems));
        }
        presentItems = presentItems + perPageItems;
    });
  }
}

Result

Result data

Alok
  • 8,452
  • 13
  • 55
  • 93
  • 1
    isn't a bad practice useing setState in initState function? – Giacomo M Jul 29 '20 at 08:14
  • I have referred to [this](https://stackoverflow.com/a/53373017/5362583), and found out, it is indeed not a good practise. However, you can try setting the value of `present` via normal approach. It will serve your purpose. Thanks @GiacomoM for bringing this up :) – Alok Jul 29 '20 at 08:23
  • Hey @GiacomoM, I have removed the `setState` inside `initState()`, and tested the code. It works fine, so you can refer to the code now. It is clean, and uses the best practise of `Flutter Dev`. Thanks again! Cheers :) – Alok Jul 29 '20 at 08:26
  • Hey @GiacomoM, I am more interested to know whether it worked for you not. Since I got no response from your side after that. I would be really happy to know if my answer was of any help to you :) – Alok Jul 31 '20 at 05:28