Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ScrollController listenable maxScrollExtent #21541

Closed
florisvdg opened this issue Sep 7, 2018 · 16 comments · Fixed by #57670
Closed

ScrollController listenable maxScrollExtent #21541

florisvdg opened this issue Sep 7, 2018 · 16 comments · Fixed by #57670
Assignees
Labels
c: new feature Nothing broken; request for a new capability customer: crowd Affects or could affect many people, though not necessarily a specific customer. f: material design flutter/packages/flutter/material repository. f: scrolling Viewports, list views, slivers, etc. framework flutter/packages/flutter repository. See also f: labels.

Comments

@florisvdg
Copy link

Use case: a ListView that supports loading in new items from the top and also from the bottom, like a Twitter timeline or an RSS feed. When dynamically adding new items at the bottom, everything is fine. However, when adding items from the top (in the case of a Twitter or RSS pull-to-refresh or a real time feed), the newly added items, from the perspective of the user, push the scroll position down, because the scroll content height has increased, resulting in a jump (or in the case of an AnimatedList: a slide animation). The user would just expect the scroll position to be at the same item the user is looking at at that moment.

Because Flutter does not seem to have anything for this use case out of the box, a way to fix this issue is to just recalculate the scroll offset when the new items are added and then call scrollController.jumpTo upon an updated state. This is easy when you know the item size in advance. When the items have content dependent heights the calculation can be done using the previous maxScrollExtent and the new maxScrollExtent. However, when to then run this calculation seems to be a harder issue.
I tried invoking it

  • right after setState, but that seems to be too early, because the maxScrollExtent is not known and not updated at that time
  • using WidgetsBinding.instance.addPostFrameCallback, which works and sets the scroll offset to the desired position, but seems to do this too late, causing the scroll offset to quickly jump

Being able to listen for when the maxScrollExtent is actually updated could solve this issue. Or would there be an alternative way to do this? Seems like a pretty basic problem any serious social, twitter, news, rss app would run into.

@zoechi zoechi added c: new feature Nothing broken; request for a new capability framework flutter/packages/flutter repository. See also f: labels. f: material design flutter/packages/flutter/material repository. labels Sep 7, 2018
@zoechi
Copy link
Contributor

zoechi commented Sep 7, 2018

Related or similar #12319

@zoechi zoechi added the f: scrolling Viewports, list views, slivers, etc. label Feb 14, 2019
@zoechi zoechi added this to the Goals milestone Feb 14, 2019
@espedale
Copy link

What is the status on the fix for this issue??? This makes my app look very clunky! Please provide a solution for this, Flutter!

@tudor07
Copy link

tudor07 commented Oct 29, 2019

I am also impacted by this. It's a very common use case to add items to the top of a list. All possible workaround are not ideal because the list jumps around.

Any solution for this?

@gerry05
Copy link

gerry05 commented Dec 12, 2019

I'm making a chat room for multiple users and I'm having this problem. Please let me know if anyone has solved this issue. Thanks!

@esDotDev
Copy link

+1, this would all be fixed by a getOffsetForIndex() API, which is sorely missing right now anyways.

We really shouldn't need to measure previous and current extents in order to just jump to a specific index. If I was at index 0, and loaded 15 new items at the front if my list, I should simply be able to call controller.jumpToIndex(15) or controller.jumpTo(controller.getOffsetForIndex(15)) to maintain scroll position.

Both would be nice :)

@tudor07
Copy link

tudor07 commented Mar 26, 2020

@zoechi any updates on this? it's been two years, I'm still struggling with this...
@florisvdg did you fix this?

@VladyslavBondarenko VladyslavBondarenko added the customer: crowd Affects or could affect many people, though not necessarily a specific customer. label Mar 27, 2020
@florisvdg
Copy link
Author

florisvdg commented Mar 29, 2020

@florisvdg did you fix this?

@tudor07 I "fixed" it by shaping our requirements to allow for all list items to be of the same height...

@clocksmith clocksmith added this to Backlog in Material Flutter - Sprint 36 via automation Apr 23, 2020
@clocksmith clocksmith moved this from Backlog to Sprint + 1 in Material Flutter - Sprint 36 May 7, 2020
@clocksmith clocksmith moved this from Sprint + 1 to Current Sprint in Material Flutter - Sprint 36 May 12, 2020
@perclasson
Copy link
Contributor

perclasson commented May 15, 2020

This can done with a CustomScrollView and two slivers SliverList. You'll want to set the CustomScrollView.center to the key of the second sliver. Then when you want to add content above the screen: add it to the first sliver. When you want content below the screen: add it to the the second sliver.

I made an example (add content below and above with the plus in the top left corner): https://dartpad.dartlang.org/c3b9b03925cdaaf88c1b8fe78a3b96b0

@florisvdg @tudor07 Does this solution solve the problem for you? I'll go ahead and close the ticket unless you think otherwise.

Material Flutter - Sprint 36 automation moved this from Current Sprint to Done May 15, 2020
@gskinner-shared
Copy link

While it solves this very specific use case, it does not address.the API limitation of scroll view that was the heart of the issue. Why not give us a simple event when maxExtents changes?

@perclasson perclasson reopened this May 15, 2020
Material Flutter - Sprint 36 automation moved this from Done to Backlog May 15, 2020
@perclasson perclasson moved this from Backlog to Current Sprint in Material Flutter - Sprint 36 May 15, 2020
@HansMuller
Copy link
Contributor

@gskinner-shared - as @florisvdg pointed out, building a solution to this problem around reacting to the update of maxScrollExtent is tricky because the notification comes at layout time and ScrollController.jumpTo(), which - generally speaking - could trigger an additional layout, is going to affect the next frame.

The solution suggested by @perclasson is relatively straightforward and nicely addresses this issue's use-case.

I think we should close this issue upon adding a version of the sample solution to the CustomScrollView API docs.

@esDotDev
Copy link

esDotDev commented May 21, 2020

It's a pretty common use case to need to know the accurate size of the scroll contents. Especially when building scrollbars.

What we do now is basically hack around it using sheduleMicrotask, or create some system where the child tells us it's extent (via Notification or post-build callback). Seems like a proper event would at least be preferable to that even if it's async? Our workarounds are all async anyways...

@clocksmith clocksmith moved this from Done to Done in Previous Sprints in Material Flutter - Sprint 36 May 27, 2020
@HeckYeah-01
Copy link

@perclasson , I would like to thank you so much for addressing this important topic. I've tried this with SliverAppBar and I couldn't maintain the right behavior as floating = true.

how can I handle SliverAppBar on CustomScrollView in this example?

@HeckYeah-01
Copy link

@perclasson just FYI, I had some success in embedding SliverAppbar using NestedScrollViews but won't float because the issue Support Floating+ SliverAppBars in NestedScrollViews #57707

Still have an issue with a jump back to the top of the screen, because with the approach it won't 0.0 it goes with minimize, even using minScrollExtent won't get into all top.

@HeckYeah-01
Copy link

I was successfully able to jump to the top with

_scrollController.position.minScrollExtent - MediaQuery.of(context).size.height;

Actually, I don't the reason exactly just went further than the minScrollExtent

@perclasson
Copy link
Contributor

@HickYeah Looks like you manage to solve the issue!

Here is something similar to what you need, but with the solution of using two [SliverList]s: https://dartpad.dartlang.org/38a9320bb8edd30af3c8543c24df8a21

For future questions, I suggest asking in the discord/slack channel for Flutter, or create a new issue with your feature requests.

@github-actions
Copy link

This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of flutter doctor -v and a minimal reproduction of the issue.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Aug 15, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
c: new feature Nothing broken; request for a new capability customer: crowd Affects or could affect many people, though not necessarily a specific customer. f: material design flutter/packages/flutter/material repository. f: scrolling Viewports, list views, slivers, etc. framework flutter/packages/flutter repository. See also f: labels.
Projects
No open projects
Material Flutter - Sprint 36
  
Done in Previous Sprints
12 participants