You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Scroll to the end of a ListView with a PageStorageKey
Remove one or more items from the list
Navigate away from the ListView
Navigate back to the ListView so that it gets rebuilt
Expected results
The rebuilt ListView immediately appears with its last scroll position restored.
Actual results
The rebuilt ListView appears with an animation to the last scroll position (BallisticScrollActivity).
Workarounds
A workaround I've found is to call ScrollPosition.pointerScroll() after each list item removal (implemented for List Two in the sample code).
But this is harder to achieve if the list update happens in an async fashion and can't be awaited (eg. when using a database update stream).
This workaround reveals the underlying issue: ListView.builder does not update its scroll position when itemCount is reduced
and the position becomes greater than the actual maxScrollExtent. It is only updated when the position stored in its PageStorageKey is restored which then becomes visible with a BallisticScrollActivity.
Another workaround is to detect this situation in a ScrollController and move the position without animation:
Workaround with CustomScrollController
classCustomScrollControllerextendsScrollController {
bool _firstChangeWithDimensionsSeen =false;
@overrideScrollControllerCallback?get onAttach => (position) {
position.addListener(() =>_onPositionChange(position));
};
void_onPositionChange(ScrollPosition position) {
if (!_firstChangeWithDimensionsSeen && position.haveDimensions) {
// detect restoration of a scroll position that would result in an unwanted animationif (position.pixels > position.maxScrollExtent) {
position.jumpTo(position.maxScrollExtent);
}
_firstChangeWithDimensionsSeen =true;
}
}
}
However, this issue still feels like something that should be handled at the framework level and not by developers themselves.
Screenshots / Video demonstrationScroll.position.issue.mp4
Logs
No response
Flutter Doctor output
Doctor output
[✓] Flutter (Channel stable, 3.29.3, on macOS 14.3.1 23D60 darwin-arm64, locale de-CH) [310ms] • Flutter version 3.29.3 on channel stable at /Users/user/fvm/versions/3.29.3 • Upstream repository https://github.com/flutter/flutter.git • Framework revision ea121f8859 (2 weeks ago), 2025-04-11 19:10:07 +0000 • Engine revision cf56914b32 • Dart version 3.7.2 • DevTools version 2.42.3[!] Android toolchain - develop for Android devices (Android SDK version 34.0.0) [349ms] • Android SDK at /Users/user/Library/Android/sdk ✗ cmdline-tools component is missing Run `path/to/sdkmanager --install "cmdline-tools;latest"` See https://developer.android.com/studio/command-line for more details. ✗ Android license status unknown. Run `flutter doctor --android-licenses` to accept the SDK licenses. See https://flutter.dev/to/macos-android-setup for more details.[✓] Xcode - develop for iOS and macOS (Xcode 15.3) [863ms] • Xcode at /Applications/Xcode.app/Contents/Developer • Build 15E204a • CocoaPods version 1.16.2[✓] Chrome - develop for the web [9ms] • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome[✓] Android Studio (version 2024.1) [9ms] • Android Studio at /Applications/Android Studio.app/Contents • Flutter plugin can be installed from: 🔨 https://plugins.jetbrains.com/plugin/9212-flutter • Dart plugin can be installed from: 🔨 https://plugins.jetbrains.com/plugin/6351-dart • Java version OpenJDK Runtime Environment (build 17.0.11+0-17.0.11b1207.24-11852314)[✓] VS Code (version 1.97.2) [7ms] • VS Code at /Applications/Visual Studio Code.app/Contents • Flutter extension version 3.108.0[✓] Network resources [1’432ms] • All expected network resources are available.! Doctor found issues in 1 category.
Steps to reproduce
Expected results
The rebuilt ListView immediately appears with its last scroll position restored.
Actual results
The rebuilt ListView appears with an animation to the last scroll position (BallisticScrollActivity).
Workarounds
A workaround I've found is to call ScrollPosition.pointerScroll() after each list item removal (implemented for List Two in the sample code).
But this is harder to achieve if the list update happens in an async fashion and can't be awaited (eg. when using a database update stream).
This workaround reveals the underlying issue: ListView.builder does not update its scroll position when itemCount is reduced
and the position becomes greater than the actual maxScrollExtent. It is only updated when the position stored in its PageStorageKey is restored which then becomes visible with a BallisticScrollActivity.
Another workaround is to detect this situation in a ScrollController and move the position without animation:
Workaround with CustomScrollController
However, this issue still feels like something that should be handled at the framework level and not by developers themselves.
Code sample
Code sample
Screenshots or Video
Screenshots / Video demonstration
Scroll.position.issue.mp4
Logs
No response
Flutter Doctor output
Doctor output