Repository navigation
Open
Labels
P2Important issues not at the top of the work listImportant issues not at the top of the work listf: scrollingViewports, list views, slivers, etc.Viewports, list views, slivers, etc.found in release: 3.24Found to occur in 3.24Found to occur in 3.24frameworkflutter/packages/flutter repository. See also f: labels.flutter/packages/flutter repository. See also f: labels.has reproducible stepsThe issue has been confirmed reproducible and is ready to work onThe issue has been confirmed reproducible and is ready to work onteam-frameworkOwned by Framework teamOwned by Framework teamtriaged-frameworkTriaged by Framework teamTriaged by Framework teamworkaround availableThere is a workaround available to overcome the issueThere is a workaround available to overcome the issue
Description
Steps to reproduce
https://github.com/flutter/flutter/pull/157756/files this pr, it's not fixed those issues.
- RefreshIndicator syncs scrollposition across tabs when using TabbarView with AutomaticKeepAliveClientMixin inside NestedScrollView #62833
- Combining NestedScrollView with TabBarView has problems. #81619
- NestedScrollView flutter_gallery Tabs Sample the Scroll state is not right when tab the tabbar #21868
- Using NestedScrollView, TabBarView and AutomaticKeepAliveClientMixin will scroll other scroll views in the tab. #36419
The reason is that the scroll list in NestedScrollView's body are cached, they are not removed from ScrollController, so when tap on other tab, and scroll the list, it will change all of postions in ScrollController.
Expected results
on scroll current tab list
Actual results
all of tab list are scroll
Code sample
Code sample
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(home: MyApp()));
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
@override
State<StatefulWidget> createState() {
return MyAppState();
}
}
class MyAppState extends State<MyApp> with TickerProviderStateMixin {
final List<ListItem> listData = [];
ScrollController sc = ScrollController(initialScrollOffset: 0.0);
late TabController tc;
@override
void initState() {
tc = TabController(length: 2, vsync: this);
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(appBar: AppBar(title: Text('Test')), body: getBody());
}
Widget getBody() {
return NestedScrollView(
controller: sc,
body: Column(
children: [
TabBar(tabs: [Tab(text: 'tab1'), Tab(text: 'tab2')], controller: tc),
Expanded(
child: TabBarView(
controller: tc,
children: <Widget>[
ListBuilder(name: Icons.abc, count: 40),
ListBuilder(name: Icons.accessibility, count: 50),
],
),
),
],
),
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
return [];
},
);
}
}
class ListItem {
final String title;
final IconData iconData;
ListItem(this.title, this.iconData);
}
class ListBuilder extends StatefulWidget {
final int count;
final IconData name;
const ListBuilder({required this.count, required this.name, super.key});
@override
_LoadImgByLocAppPageState createState() =>
_LoadImgByLocAppPageState(count, name);
}
class _LoadImgByLocAppPageState extends State
with AutomaticKeepAliveClientMixin {
IconData name;
_LoadImgByLocAppPageState(this.count, this.name);
int count = 20;
final List<ListItem> listData = [];
@override
void initState() {
for (int i = 0; i < count; i++) {
listData.add(ListItem("Item$i", name));
}
super.initState();
}
@override
Widget build(BuildContext context) {
super.build(context);
return SafeArea(
top: false,
bottom: false,
child: Builder(
// This Builder is needed to provide a BuildContext that is "inside"
// the NestedScrollView, so that sliverOverlapAbsorberHandleFor() can
// find the NestedScrollView.
builder: (BuildContext context) {
return CustomScrollView(
slivers: <Widget>[
SliverPadding(
padding: const EdgeInsets.all(8.0),
// In this example, the inner scroll view has
// fixed-height list items, hence the use of
// SliverFixedExtentList. However, one could use any
// sliver widget here, e.g. SliverList or SliverGrid.
sliver: SliverFixedExtentList(
// The items in this example are fixed to 48 pixels
// high. This matches the Material Design spec for
// ListTile widgets.
itemExtent: 48.0,
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
// This builder is called for each child.
// In this example, we just number each list item.
return Text(index.toString());
},
// The childCount of the SliverChildBuilderDelegate
// specifies how many children this inner list
// has. In this example, each tab has a list of
// exactly 30 items, but this is arbitrary.
childCount: listData.length,
),
),
),
],
);
},
),
);
}
@override
bool get wantKeepAlive => true;
}
Screenshots or Video
Screenshots / Video demonstration
[Upload media here]
Logs
Logs
[Paste your logs here]Flutter Doctor output
Doctor output
[✓] Flutter (Channel master, 3.27.0-1.0.pre.552, on macOS 15.1 24B83 darwin-arm64, locale
zh-Hans-CN)
• Flutter version 3.27.0-1.0.pre.552 on channel masterReacted by Shuyu Guo, Small Guo, tgpnet, Flop, 野瀬田 裕樹, JZ, maRci002, Ahmed Elsayed, TainakaDrums, 鲍远申 and 1 more
Reacted by Shuyu Guo, 野瀬田 裕樹, Nguyễn Quang Tuyến, JZ and 鲍远申
Reacted by Small Guo, JZ and 鲍远申
Metadata
Metadata
Assignees
Labels
P2Important issues not at the top of the work listImportant issues not at the top of the work listf: scrollingViewports, list views, slivers, etc.Viewports, list views, slivers, etc.found in release: 3.24Found to occur in 3.24Found to occur in 3.24frameworkflutter/packages/flutter repository. See also f: labels.flutter/packages/flutter repository. See also f: labels.has reproducible stepsThe issue has been confirmed reproducible and is ready to work onThe issue has been confirmed reproducible and is ready to work onteam-frameworkOwned by Framework teamOwned by Framework teamtriaged-frameworkTriaged by Framework teamTriaged by Framework teamworkaround availableThere is a workaround available to overcome the issueThere is a workaround available to overcome the issue
Activity
zmtzawqlp commentedon Nov 19, 2024
nate-thegrate commentedon Nov 19, 2024
@zmtzawqlp thanks for reporting this! I'm able to reproduce this problem on the current master and stable branches.
I felt that the one change likely wouldn't resolve all 5 issues; thanks for confirming that. I likely won't be able to continue the effort of fixing these bugs but am happy to help with triage.
yuukiw00w commentedon Nov 19, 2024
yuukiw00w commentedon Dec 11, 2024
Apologies to those who were expecting this fix, but I have closed my PR.
After working on this issue, I came to understand that this behavior is part of the current NestedScrollView specification. From what I can tell by reading the code, ScrollController instances associated with a NestedScrollView are expected to remain synchronized as long as they are kept alive.
Since I do not have plans to create an alternative NestedScrollView to achieve new behavior, I hope someone else will take on this challenge in the future.
yuukiw00w commentedon Dec 18, 2024
IbrokhimMirzaev commentedon Jan 25, 2025
jlzhjp commentedon Jan 26, 2025
For those who encountered this issue, please refer to this solution: #36419 (comment) by @maRci002 , based on #118713 (comment). The original DartPad link is broken; here is an updated link: https://dartpad.dev/?id=5d1a0c7c4b55281ccff377fc8ea90b60.
jlzhjp commentedon Jan 27, 2025
I'm following @AsturaPhoenix 's hint here #118713 (comment) to further optimize the solution and here we are.
Video
2025-01-28.12-32-14.mp4
Code
https://gist.github.com/jlzhjp/f32d7f4d4a72de2d90d85c7ce3510115
https://dartpad.dev/f32d7f4d4a72de2d90d85c7ce3510115
What's working out of box:
ScrollPositions do not get synchronizedRefreshIndicator(although the position is kind of weird)SliverOverlapAbsorberHandle.layoutExtentScrollbarsSince I'm not an expert, there is definitely something I'm missing. But I think it's the right way to go.
muratgorken commentedon Jun 15, 2025
I don't mean to be rude, but the problem persists. Also
NestedScrollView > Tabbar > Refresh indicator > Any scrollable widget
If a tab triggers the refresh indicator, other tabs are refreshed in the same way. Moreover, in some cases just scrolling to the top can trigger this behavior. The smallest problem for me is that tabs can't carry their own scroll position. As far as I understand, this problem has been going on since 2023 and the flutter team is not working on it. This is a big problem. Almost all modern apps use tabs and use mechanisms like refresh, load on scroll, etc. in various ways. It's really sad that Flutter can't provide this naturally.
Note: The extended_nested_scroll_view package seems to be a workaround, but it doesn't fully fix the problem and doesn't work exactly as expected.
pawdom-dev commentedon Jul 26, 2025
I strongly urge the immediate removal of the label workaround available, as it has consistently demonstrated its ineffectiveness.
I have a case involving a TabBar, but the scroll position keeps resetting. When using:
NestedScrollView ( headerSliverBuilder:SliverAppBar (bottom: TabBar), body: TabBarView(children:[RefreshIndicator(child:CustomScrollView(slivers))])I tried make workaround work for TabBar with no success.
jlzhjp commentedon Jul 28, 2025
I haven't used Flutter in a while, but the workaround still works for me. Can you give it a try?
https://dartpad.dev/f32d7f4d4a72de2d90d85c7ce3510115
pawdom-dev commentedon Jul 30, 2025