Unverified Commit 99ccff3b authored by Daniel Edrisian's avatar Daniel Edrisian Committed by GitHub

Add stretch property to CupertinoSliverNavigationBar (#71707)

* Add stretch property to CupertinoSliverNavigationBar

* Added tests

* Fix trailling spaces

* xster review: fix tests

* xster review: fix tests

* trim extra spaces
parent 78aa1056
......@@ -551,6 +551,11 @@ class _CupertinoNavigationBarState extends State<CupertinoNavigationBar> {
/// from the operating system can be retrieved in many ways, such as querying
/// [MediaQuery.textScaleFactorOf] against [CupertinoApp]'s [BuildContext].
///
/// The [stretch] parameter determines whether the nav bar should stretch to
/// fill the over-scroll area. The nav bar can still expand and contract as the
/// user scrolls, but it will also stretch when the user over-scrolls if the
/// [stretch] value is `true`. Defaults to `true`.
///
/// See also:
///
/// * [CupertinoNavigationBar], an iOS navigation bar for use on non-scrolling
......@@ -575,6 +580,7 @@ class CupertinoSliverNavigationBar extends StatefulWidget {
this.actionsForegroundColor,
this.transitionBetweenRoutes = true,
this.heroTag = _defaultHeroTag,
this.stretch = true,
}) : assert(automaticallyImplyLeading != null),
assert(automaticallyImplyTitle != null),
assert(
......@@ -672,6 +678,13 @@ class CupertinoSliverNavigationBar extends StatefulWidget {
/// True if the navigation bar's background color has no transparency.
bool get opaque => backgroundColor?.alpha == 0xFF;
/// Whether the nav bar should stretch to fill the over-scroll area.
///
/// The nav bar can still expand and contract as the user scrolls, but it will
/// also stretch when the user over-scrolls if the [stretch] value is `true`.
/// Defaults to `true`.
final bool stretch;
@override
_CupertinoSliverNavigationBarState createState() => _CupertinoSliverNavigationBarState();
}
......@@ -729,6 +742,7 @@ class _CupertinoSliverNavigationBarState extends State<CupertinoSliverNavigation
heroTag: widget.heroTag,
persistentHeight: _kNavBarPersistentHeight + MediaQuery.of(context).padding.top,
alwaysShowMiddle: widget.middle != null,
stretchConfiguration: widget.stretch ? OverScrollHeaderStretchConfiguration() : null,
),
),
),
......@@ -751,6 +765,7 @@ class _LargeTitleNavigationBarSliverDelegate
required this.heroTag,
required this.persistentHeight,
required this.alwaysShowMiddle,
required this.stretchConfiguration,
}) : assert(persistentHeight != null),
assert(alwaysShowMiddle != null),
assert(transitionBetweenRoutes != null);
......@@ -774,6 +789,9 @@ class _LargeTitleNavigationBarSliverDelegate
@override
double get maxExtent => persistentHeight + _kNavBarLargeTitleHeightExtension;
@override
OverScrollHeaderStretchConfiguration? stretchConfiguration;
@override
Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) {
final bool showLargeTitle = shrinkOffset < maxExtent - minExtent - _kNavBarShowLargeTitleThreshold;
......
......@@ -1185,6 +1185,113 @@ void main() {
expect(barItems2.length, greaterThan(0));
expect(barItems2.any((RichText t) => t.textScaleFactor != 1), isFalse);
});
testWidgets(
'CupertinoSliverNavigationBar stretches upon over-scroll and bounces back once over-scroll ends',
(WidgetTester tester) async {
const Text trailingText = Text('Bar Button');
const Text titleText = Text('Large Title');
await tester.pumpWidget(
CupertinoApp(
home: CupertinoPageScaffold(
child: CustomScrollView(
slivers: <Widget>[
const CupertinoSliverNavigationBar(
trailing: trailingText,
largeTitle: titleText,
),
SliverToBoxAdapter(
child: Container(
height: 1200.0,
),
),
],
),
),
),
);
final Finder trailingTextFinder = find.byWidget(trailingText).first;
final Finder titleTextFinder = find.byWidget(titleText).first;
final Offset initialTrailingTextToLargeTitleOffset = tester.getTopLeft(trailingTextFinder) - tester.getTopLeft(titleTextFinder);
// Drag for overscroll
await tester.drag(find.byType(Scrollable), const Offset(0.0, 150.0));
await tester.pump();
final Offset stretchedTrailingTextToLargeTitleOffset = tester.getTopLeft(trailingTextFinder) - tester.getTopLeft(titleTextFinder);
expect(
stretchedTrailingTextToLargeTitleOffset.dy.abs(),
greaterThan(initialTrailingTextToLargeTitleOffset.dy.abs())
);
// Ensure overscroll retracts to original size after releasing gesture
await tester.pumpAndSettle();
final Offset finalTrailingTextToLargeTitleOffset = tester.getTopLeft(trailingTextFinder) - tester.getTopLeft(titleTextFinder);
expect(
finalTrailingTextToLargeTitleOffset.dy.abs(),
initialTrailingTextToLargeTitleOffset.dy.abs(),
);
});
testWidgets(
'CupertinoSliverNavigationBar does not stretch upon over-scroll if stretch parameter is false',
(WidgetTester tester) async {
const Text trailingText = Text('Bar Button');
const Text titleText = Text('Large Title');
await tester.pumpWidget(
CupertinoApp(
home: CupertinoPageScaffold(
child: CustomScrollView(
slivers: <Widget>[
const CupertinoSliverNavigationBar(
trailing: trailingText,
largeTitle: titleText,
stretch: false,
),
SliverToBoxAdapter(
child: Container(
height: 1200.0,
),
),
],
),
),
),
);
final Finder trailingTextFinder = find.byWidget(trailingText).first;
final Finder titleTextFinder = find.byWidget(titleText).first;
final Offset initialTrailingTextToLargeTitleOffset = tester.getTopLeft(trailingTextFinder) - tester.getTopLeft(titleTextFinder);
// Drag for overscroll
await tester.drag(find.byType(Scrollable), const Offset(0.0, 150.0));
await tester.pump();
final Offset stretchedTrailingTextToLargeTitleOffset = tester.getTopLeft(trailingTextFinder) - tester.getTopLeft(titleTextFinder);
expect(
stretchedTrailingTextToLargeTitleOffset.dy.abs(),
initialTrailingTextToLargeTitleOffset.dy.abs(),
);
// Ensure overscroll is zero after releasing gesture
await tester.pumpAndSettle();
final Offset finalTrailingTextToLargeTitleOffset = tester.getTopLeft(trailingTextFinder) - tester.getTopLeft(titleTextFinder);
expect(
finalTrailingTextToLargeTitleOffset.dy.abs(),
initialTrailingTextToLargeTitleOffset.dy.abs(),
);
});
}
class _ExpectStyles extends StatelessWidget {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment