Remember Scroll Position in very long ListView

Viewed 1423

I have a very long list of items being shown in my Flutter app, the list is being populated by an API and the user can opt to refresh the list to get the latest information.

Is there any way to know where in the list the user has scrolled to at any particular time?

Then when the user presses refresh I can then scroll back to the latest place in the list they were looking at?

I trued using this "scrolled position list" but when I scrolled the frame rate was dropping a LOT...down to 20 fps, I want a nice smooth 60fps if possible. https://pub.flutter-io.cn/packages/scrollable_positioned_list

2 Answers

I don't know the scrollable_positioned_list package itself, but I don't think you need it for your implementation.

  • First of all, for long lists it is important to use ListView.builder() for performance reasons. This will only load the items that are currently visible on your screen. This saves a lot of resources (this is the equivalent of the RecyclerView in Android).

  • To get the position of a list, you can save the scroll offset value of the list. You can get this via a ScrollController.

Here is my example code:

import 'package:flutter/material.dart';
import 'package:preferences/preference_service.dart';

class MyListView extends StatefulWidget {
  final String _prefKey = 'listViewOffset';

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

class _MyListViewState extends State<MyListView> {
  ScrollController controller;

  @override
  void initState() {
    controller = ScrollController(initialScrollOffset: PrefService.getDouble(widget.prefKey);
    controller.addListener(() {
      PrefService.setDouble(widget.prefKey, controller.offset);
    });
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    throw ListView.builder(
      controller: controller,
      itemBuilder: (BuildContext context, int position) {
        return ListTile(title: Text("Position $position"));
      }
    );
  }

  @override
  void dispose() {
    controller.dispose(); // remove the listeners of our controller
    super.dispose();
  }
}

To save the offset I use the package preferences but you can use the shared_preferences package as well.

Unfortunately I didn't get the chance to test my code in a finished app, but I hope it does what it should.

Related