mirror of
https://github.com/flutter/flutter
synced 2024-10-12 11:12:54 +00:00
Include forceElevated for scrolledUnder in new SliverAppBar variants (#104536)
This commit is contained in:
parent
2e7cea6dfe
commit
fe04647651
|
@ -1284,7 +1284,7 @@ class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate {
|
|||
final double extraToolbarHeight = math.max(minExtent - _bottomHeight - topPadding - (toolbarHeight ?? kToolbarHeight), 0.0);
|
||||
final double visibleToolbarHeight = visibleMainHeight - _bottomHeight - extraToolbarHeight;
|
||||
|
||||
final bool isScrolledUnder = overlapsContent || (pinned && shrinkOffset > maxExtent - minExtent);
|
||||
final bool isScrolledUnder = overlapsContent || forceElevated || (pinned && shrinkOffset > maxExtent - minExtent);
|
||||
final bool isPinnedWithOpacityFade = pinned && floating && bottom != null && extraToolbarHeight == 0.0;
|
||||
final double toolbarOpacity = !pinned || isPinnedWithOpacityFade
|
||||
? clampDouble(visibleToolbarHeight / (toolbarHeight ?? kToolbarHeight), 0.0, 1.0)
|
||||
|
@ -1308,7 +1308,7 @@ class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate {
|
|||
)
|
||||
: flexibleSpace,
|
||||
bottom: bottom,
|
||||
elevation: forceElevated || isScrolledUnder ? elevation : 0.0,
|
||||
elevation: isScrolledUnder ? elevation : 0.0,
|
||||
scrolledUnderElevation: scrolledUnderElevation,
|
||||
shadowColor: shadowColor,
|
||||
surfaceTintColor: surfaceTintColor,
|
||||
|
|
|
@ -2552,8 +2552,175 @@ void main() {
|
|||
expect(scrollStarted, 2);
|
||||
expect(scrollEnded, 2);
|
||||
});
|
||||
|
||||
testWidgets('SliverAppBar.medium collapses in NestedScrollView', (WidgetTester tester) async {
|
||||
final GlobalKey<NestedScrollViewState> nestedScrollView = GlobalKey();
|
||||
const double collapsedAppBarHeight = 64;
|
||||
const double expandedAppBarHeight = 112;
|
||||
|
||||
await tester.pumpWidget(MaterialApp(
|
||||
home: Scaffold(
|
||||
body: NestedScrollView(
|
||||
key: nestedScrollView,
|
||||
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
|
||||
return <Widget>[
|
||||
SliverOverlapAbsorber(
|
||||
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
|
||||
sliver: SliverAppBar.medium(
|
||||
title: const Text('AppBar Title'),
|
||||
),
|
||||
),
|
||||
];
|
||||
},
|
||||
body: Builder(
|
||||
builder: (BuildContext context) {
|
||||
return CustomScrollView(
|
||||
slivers: <Widget>[
|
||||
SliverOverlapInjector(handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context)),
|
||||
SliverFixedExtentList(
|
||||
itemExtent: 50.0,
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
(BuildContext context, int index) => ListTile(title: Text('Item $index')),
|
||||
childCount: 30,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
));
|
||||
|
||||
// There are two widgets for the title.
|
||||
final Finder expandedTitle = find.text('AppBar Title').last;
|
||||
final Finder expandedTitleClip = find.ancestor(
|
||||
of: expandedTitle,
|
||||
matching: find.byType(ClipRect),
|
||||
);
|
||||
|
||||
// Default, fully expanded app bar.
|
||||
expect(nestedScrollView.currentState?.outerController.offset, 0);
|
||||
expect(nestedScrollView.currentState?.innerController.offset, 0);
|
||||
expect(find.byType(SliverAppBar), findsOneWidget);
|
||||
expect(appBarHeight(tester), expandedAppBarHeight);
|
||||
expect(tester.getSize(expandedTitleClip).height, expandedAppBarHeight - collapsedAppBarHeight);
|
||||
|
||||
// Scroll the expanded app bar partially out of view.
|
||||
final Offset point1 = tester.getCenter(find.text('Item 5'));
|
||||
await tester.dragFrom(point1, const Offset(0.0, -45.0));
|
||||
await tester.pump();
|
||||
expect(nestedScrollView.currentState?.outerController.offset, 45.0);
|
||||
expect(nestedScrollView.currentState?.innerController.offset, 0.0);
|
||||
expect(find.byType(SliverAppBar), findsOneWidget);
|
||||
expect(appBarHeight(tester), expandedAppBarHeight - 45);
|
||||
expect(tester.getSize(expandedTitleClip).height, expandedAppBarHeight - collapsedAppBarHeight - 45);
|
||||
|
||||
// Scroll so that it is completely collapsed.
|
||||
await tester.dragFrom(point1, const Offset(0.0, -555.0));
|
||||
await tester.pump();
|
||||
expect(nestedScrollView.currentState?.outerController.offset, 48.0);
|
||||
expect(nestedScrollView.currentState?.innerController.offset, 552.0);
|
||||
expect(find.byType(SliverAppBar), findsOneWidget);
|
||||
expect(appBarHeight(tester), collapsedAppBarHeight);
|
||||
expect(tester.getSize(expandedTitleClip).height, 0);
|
||||
|
||||
// Scroll back to fully expanded.
|
||||
await tester.dragFrom(point1, const Offset(0.0, 600.0));
|
||||
await tester.pump();
|
||||
expect(nestedScrollView.currentState?.outerController.offset, 0);
|
||||
expect(nestedScrollView.currentState?.innerController.offset, 0);
|
||||
expect(find.byType(SliverAppBar), findsOneWidget);
|
||||
expect(appBarHeight(tester), expandedAppBarHeight);
|
||||
expect(tester.getSize(expandedTitleClip).height, expandedAppBarHeight - collapsedAppBarHeight);
|
||||
});
|
||||
|
||||
testWidgets('SliverAppBar.large collapses in NestedScrollView', (WidgetTester tester) async {
|
||||
final GlobalKey<NestedScrollViewState> nestedScrollView = GlobalKey();
|
||||
const double collapsedAppBarHeight = 64;
|
||||
const double expandedAppBarHeight = 152;
|
||||
|
||||
await tester.pumpWidget(MaterialApp(
|
||||
home: Scaffold(
|
||||
body: NestedScrollView(
|
||||
key: nestedScrollView,
|
||||
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
|
||||
return <Widget>[
|
||||
SliverOverlapAbsorber(
|
||||
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
|
||||
sliver: SliverAppBar.large(
|
||||
title: const Text('AppBar Title'),
|
||||
forceElevated: innerBoxIsScrolled,
|
||||
),
|
||||
),
|
||||
];
|
||||
},
|
||||
body: Builder(
|
||||
builder: (BuildContext context) {
|
||||
return CustomScrollView(
|
||||
slivers: <Widget>[
|
||||
SliverOverlapInjector(handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context)),
|
||||
SliverFixedExtentList(
|
||||
itemExtent: 50.0,
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
(BuildContext context, int index) => ListTile(title: Text('Item $index')),
|
||||
childCount: 30,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
));
|
||||
|
||||
// There are two widgets for the title.
|
||||
final Finder expandedTitle = find.text('AppBar Title').last;
|
||||
final Finder expandedTitleClip = find.ancestor(
|
||||
of: expandedTitle,
|
||||
matching: find.byType(ClipRect),
|
||||
);
|
||||
|
||||
// Default, fully expanded app bar.
|
||||
expect(nestedScrollView.currentState?.outerController.offset, 0);
|
||||
expect(nestedScrollView.currentState?.innerController.offset, 0);
|
||||
expect(find.byType(SliverAppBar), findsOneWidget);
|
||||
expect(appBarHeight(tester), expandedAppBarHeight);
|
||||
expect(tester.getSize(expandedTitleClip).height, expandedAppBarHeight - collapsedAppBarHeight);
|
||||
|
||||
// Scroll the expanded app bar partially out of view.
|
||||
final Offset point1 = tester.getCenter(find.text('Item 5'));
|
||||
await tester.dragFrom(point1, const Offset(0.0, -45.0));
|
||||
await tester.pump();
|
||||
expect(nestedScrollView.currentState?.outerController.offset, 45.0);
|
||||
expect(nestedScrollView.currentState?.innerController.offset, 0);
|
||||
expect(find.byType(SliverAppBar), findsOneWidget);
|
||||
expect(appBarHeight(tester), expandedAppBarHeight - 45);
|
||||
expect(tester.getSize(expandedTitleClip).height, expandedAppBarHeight - collapsedAppBarHeight - 45);
|
||||
|
||||
// Scroll so that it is completely collapsed.
|
||||
await tester.dragFrom(point1, const Offset(0.0, -555.0));
|
||||
await tester.pump();
|
||||
expect(nestedScrollView.currentState?.outerController.offset, 88.0);
|
||||
expect(nestedScrollView.currentState?.innerController.offset, 512.0);
|
||||
expect(find.byType(SliverAppBar), findsOneWidget);
|
||||
expect(appBarHeight(tester), collapsedAppBarHeight);
|
||||
expect(tester.getSize(expandedTitleClip).height, 0);
|
||||
|
||||
// Scroll back to fully expanded.
|
||||
await tester.dragFrom(point1, const Offset(0.0, 600.0));
|
||||
await tester.pump();
|
||||
expect(nestedScrollView.currentState?.outerController.offset, 0);
|
||||
expect(nestedScrollView.currentState?.innerController.offset, 0);
|
||||
expect(find.byType(SliverAppBar), findsOneWidget);
|
||||
expect(appBarHeight(tester), expandedAppBarHeight);
|
||||
expect(tester.getSize(expandedTitleClip).height, expandedAppBarHeight - collapsedAppBarHeight);
|
||||
});
|
||||
}
|
||||
|
||||
double appBarHeight(WidgetTester tester) => tester.getSize(find.byType(AppBar, skipOffstage: false)).height;
|
||||
|
||||
class TestHeader extends SliverPersistentHeaderDelegate {
|
||||
const TestHeader({ this.key });
|
||||
final Key? key;
|
||||
|
|
Loading…
Reference in a new issue