Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to Keep the ScrollPosition while inserting items at the Front?

Tags:

flutter

dart

What I want

I want to create a behavior like Twitter App. So I scroll to the top of my list, I use a CupertinoSliverRefreshControl to load new posts and want to place them on top of my current shown list with keeping my ScrollPosition.

What my code looks like

To make usage of the CupertinoSliverRefreshControl I need to use slivers in a CustomScrollView. onRefresh I load new posts and add the old posts to it:

final _scrollController = ScrollController(keepScrollOffset: true);


return CustomScrollView(
  controller: _scrollController
  physics: const BouncingScrollPhysics(parent: AlwaysScrollableScrollPhysics()),
  slivers: <Widget>[
    CupertinoSliverRefreshControl(
      onRefresh: () {
        // loading new posts. I set state with blocBuilder but for easiness I show it with setState here:
        setState(() { posts = List.from(newPosts..addAll(posts)); })
      }
    ),
    SliverList(
      delegate: SliverChildBuilderDelegate((context, index) {
        return PostCard(posts[index]);
      },
      childCount: posts.length)
    )
  ]
);

What my problem is

Saving the ScrollPosition with a ScrollController is not working because it always saves the offset to the top and not to the bottom. In my case, the offset to the top will change by loading new posts.

What I've tried

I also tried to build the old posts and the new posts in two different SliverLists. To the SliverList with old posts, I added a key and set the center of my CustomScrollViewto this key. Doing so crashes my CupertinoSliverRefreshControl.

Also, I cannot just use the list reversed because I want a loading into the other direction as well in a further development state.

like image 232
Sonius Avatar asked Sep 18 '25 05:09

Sonius


1 Answers

You can use ScrollController.position for this:

// You will need to place the following code snippets in appropriate locations.
double extentAfter;

// Save the current offset from the bottom:
extentAfter = _scrollController.position.extentAfter;


// After your loading is done, you can apply the saved extentAfter:
_scrollController.jumpTo(_scrollController.position.maxScrollExtent - extentAfter);

I do not exactly know how your setup works, but I could imagine that saving the extentAfter can be done in a listener of your ScrollController (because you want to have the latest extentAfter before the new items are inserted) and jumping to the "new" position when rebuilding the scroll view.

You can not call jumpTo when rebuilding by supplying a new ScrollController:

// Update your scroll controller with the new position.
_scrollController = ScrollController(
  initialScrollOffset: _scrollController.position.maxScrollExtent - extentAfter
);
like image 79
creativecreatorormaybenot Avatar answered Sep 20 '25 21:09

creativecreatorormaybenot