Repository navigation
NestedScrollView does not work well with floated app bars on the outside or pinned app bars on the inside #11222
Copy link
Copy link
Closed
Labels
f: scrollingViewports, list views, slivers, etc.Viewports, list views, slivers, etc.frameworkflutter/packages/flutter repository. See also f: labels.flutter/packages/flutter repository. See also f: labels.
Description
Video with issue:
I made app bar background semi transparent to see that inner scroll container scrolled under pinned part of AppBar
Code to Reproduce
class TestPage2 extends StatefulWidget {
@override
_TestPageState2 createState() => new _TestPageState2();
}
class _TestPageState2 extends State<TestPage2> {
Widget _buildItem(BuildContext context, int index) {
return new ListTile(
title: new Text('Title $index'),
subtitle: new Text('Subtitle $index'),
);
}
Widget _buildTab(int listSize) {
return new TabBarView(
children: [
new Stack(
children: <Widget>[
new Positioned(
top: 0.0,
left: 0.0,
right: 0.0,
child: new Material(
elevation: 4.0,
color: Colors.white,
child: new Container(
height: 48.0,
child: new Center(
child: const Text('Here my fixed header 1')),
),
),
),
new Positioned(
top: 48.0,
left: 0.0,
right: 0.0,
bottom: 0.0,
child: new RefreshIndicator(
onRefresh: () {},
child: new ListView.builder(
itemBuilder: _buildItem,
itemCount: listSize,
)
),
),
],
),
new Stack(
children: <Widget>[
new Positioned(
top: 0.0,
left: 0.0,
right: 0.0,
child: new Material(
elevation: 4.0,
color: Colors.white,
child: new Container(
height: 48.0,
child: new Center(
child: const Text('Here my fixed header 2')),
),
),
),
new Positioned(
top: 48.0,
left: 0.0,
right: 0.0,
bottom: 0.0,
child: new RefreshIndicator(
onRefresh: () {},
child: new ListView.builder(
itemBuilder: _buildItem,
itemCount: 5,
)
),
),
],
),
],
);
}
@override
Widget build(BuildContext context) {
return new DefaultTabController(
length: 2,
child: new Scaffold(
body: new NestedScrollView(
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
return [
new SliverAppBar(
backgroundColor: Colors.black26,
title: new Text('Here title'),
pinned: true,
floating: true,
bottom: new TabBar(
tabs: [
new Tab(text: 'Tab1'),
new Tab(text: 'Tab2'),
]
),
),
];
},
body: new TabBarView(
children: [
_buildTab(30),
_buildTab(5),
],
),
),
),
);
}
}Flutter Doctor
[✓] Flutter (on Mac OS X 10.12.5 16F73, locale en-NZ, channel master)
• Flutter at /Users/nonameden/Documents/flutter
• Framework revision cf96c7db4a (2 hours ago), 2017-07-13 16:19:11 -0700
• Engine revision 431a251151
• Tools Dart version 1.25.0-dev.4.0
[✓] Android toolchain - develop for Android devices (Android SDK 26.0.0)
• Android SDK at /Users/nonameden/Library/Android/sdk
• Platform android-26, build-tools 26.0.0
• Java binary at: /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java
• Java version OpenJDK Runtime Environment (build 1.8.0_112-release-b06)
[✓] iOS toolchain - develop for iOS devices (Xcode 8.3.3)
• Xcode at /Applications/Xcode.app/Contents/Developer
• Xcode 8.3.3, Build version 8E3004b
• ios-deploy 1.9.1
• CocoaPods version 1.2.1
[✓] Android Studio
• Android Studio at /Applications/Android Studio 2.4 Preview.app/Contents
• Java version OpenJDK Runtime Environment (build 1.8.0_112-release-b736)
[✓] Android Studio
• Android Studio at /Applications/Android Studio 3.0 Preview.app/Contents
• Java version OpenJDK Runtime Environment (build 1.8.0_152-release-884-b01)
[✓] Android Studio (version 2.3)
• Android Studio at /Applications/Android Studio.app/Contents
• Java version OpenJDK Runtime Environment (build 1.8.0_112-release-b06)
[✓] IntelliJ IDEA Ultimate Edition (version 2017.1.5)
• Flutter plugin version 15.1
• Dart plugin version 171.4694.29
[✓] Connected devices
• Android SDK built for x86 • emulator-5554 • android-x86 • Android 7.0 (API 24) (emulator)
Might be a Fix
I was playing with Nested Scroll View and found that scrollExtent for outer scroll does not respect minExtent from SliverAppBar delegate so I modified RenderSliverFloatingPinnedPersistentHeader:
abstract class RenderSliverFloatingPinnedPersistentHeader extends RenderSliverFloatingPersistentHeader {
RenderSliverFloatingPinnedPersistentHeader({
RenderBox child,
FloatingHeaderSnapConfiguration snapConfiguration,
}) : super(child: child, snapConfiguration: snapConfiguration);
@override
double updateGeometry() {
final double minExtent = this.maxExtent;
final double maxExtent = this.maxExtent;
final double paintExtent = (maxExtent - _effectiveScrollOffset);
final double layoutExtent = (maxExtent - constraints.scrollOffset);
geometry = new SliverGeometry(
scrollExtent: maxExtent,
paintExtent: paintExtent.clamp(minExtent, constraints.remainingPaintExtent),
layoutExtent: layoutExtent.clamp(0.0, constraints.remainingPaintExtent - minExtent),
maxPaintExtent: maxExtent,
hasVisualOverflow: true, // Conservatively say we do have overflow to avoid complexity.
);
return 0.0;
}
}to
abstract class RenderSliverFloatingPinnedPersistentHeader extends RenderSliverFloatingPersistentHeader {
RenderSliverFloatingPinnedPersistentHeader({
RenderBox child,
FloatingHeaderSnapConfiguration snapConfiguration,
}) : super(child: child, snapConfiguration: snapConfiguration);
@override
double updateGeometry() {
final double minExtent = this.minExtent;
final double maxExtent = this.maxExtent;
final double paintExtent = (maxExtent - _effectiveScrollOffset);
final double layoutExtent = (maxExtent - constraints.scrollOffset);
geometry = new SliverGeometry(
scrollExtent: maxExtent - minExtent,
paintExtent: paintExtent.clamp(minExtent, constraints.remainingPaintExtent),
layoutExtent: layoutExtent.clamp(0.0, constraints.remainingPaintExtent - minExtent),
maxPaintExtent: maxExtent,
hasVisualOverflow: true, // Conservatively say we do have overflow to avoid complexity.
);
return 0.0;
}
}result for this on video: https://youtu.be/1y210APVEwo
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
f: scrollingViewports, list views, slivers, etc.Viewports, list views, slivers, etc.frameworkflutter/packages/flutter repository. See also f: labels.flutter/packages/flutter repository. See also f: labels.
Activity
HansMuller commentedon Jul 14, 2017
Thanks for the test-case and suggested fix, I'm looking at this now.
HansMuller commentedon Jul 14, 2017
I think the effect your change produces is correct. I extended it to handle pinned but not floating persistent header slivers which caused a bunch of tests to fail. I'll be looking into that, as well writing some new tests to verify the new behavior., next week.
I put a slightly modified version of your test app here: https://gist.github.com/HansMuller/facae02ce97892eaa2f159ea50c45e61
It just has one TabBarView, I'm guessing that you didn't mean to nest them.
nonameden commentedon Jul 15, 2017
Thank you @HansMuller , yep it supposed to be one
TabBarView, I just made a mistake during modifing code here after pasting, sorry for confusing.[-]Can't position anything to the top of tab content when using SliverAppBar with pinned+floating mode[/-][+]NestedScrollView does not work well with floated app bars on the outside or pinned app bars on the inside[/+]Hixie commentedon Feb 2, 2018
I looked at this also and it seems that additional work is going to be needed to make NestedScrollView really work properly with pinned app bars and so forth.
Maybe the absorber needs to absorb more, e.g. it should probably absorb the overlap and inject it on the inside, so that pinned app bars can follow an injector correctly...
http://junkyard.damowmow.com/589 is what I had when I stopped working on this bug.
goderbauer commentedon Dec 28, 2018
Closing this one in favor of the more popular issue #17518.
Manual engine roll 20b4ec7..21ae926
github-actions commentedon Aug 15, 2021
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 -vand a minimal reproduction of the issue.