diff --git a/packages/flutter/lib/src/cupertino/nav_bar.dart b/packages/flutter/lib/src/cupertino/nav_bar.dart index 283cc8058c..488c62b2e3 100644 --- a/packages/flutter/lib/src/cupertino/nav_bar.dart +++ b/packages/flutter/lib/src/cupertino/nav_bar.dart @@ -20,6 +20,7 @@ import 'icons.dart'; import 'page_scaffold.dart'; import 'route.dart'; import 'search_field.dart'; +import 'sheet.dart'; import 'theme.dart'; /// Modes that determine how to display the navigation bar's bottom in relation to scroll events. @@ -212,7 +213,9 @@ bool _isTransitionable(BuildContext context) { // Fullscreen dialogs never transitions their nav bar with other push-style // pages' nav bars or with other fullscreen dialog pages on the way in or on // the way out. - return route is PageRoute && !route.fullscreenDialog; + return route is PageRoute && + !route.fullscreenDialog && + !CupertinoSheetRoute.hasParentSheet(context); } /// An iOS-styled navigation bar. @@ -1571,7 +1574,10 @@ class _PersistentNavigationBar extends StatelessWidget { final Widget? backChevron = components.backChevron; final Widget? backLabel = components.backLabel; - if (leading == null && backChevron != null && backLabel != null) { + if (leading == null && + backChevron != null && + backLabel != null && + !CupertinoSheetRoute.hasParentSheet(context)) { leading = CupertinoNavigationBarBackButton._assemble(backChevron, backLabel); } @@ -1591,7 +1597,11 @@ class _PersistentNavigationBar extends StatelessWidget { return SizedBox( height: _kNavBarPersistentHeight + MediaQuery.paddingOf(context).top, - child: SafeArea(bottom: false, child: paddedToolbar), + child: SafeArea( + top: !CupertinoSheetRoute.hasParentSheet(context), + bottom: false, + child: paddedToolbar, + ), ); } } diff --git a/packages/flutter/test/cupertino/nav_bar_test.dart b/packages/flutter/test/cupertino/nav_bar_test.dart index c8fd39155d..676faecc52 100644 --- a/packages/flutter/test/cupertino/nav_bar_test.dart +++ b/packages/flutter/test/cupertino/nav_bar_test.dart @@ -461,8 +461,6 @@ void main() { testWidgets('Media padding is applied to CupertinoSliverNavigationBar', ( WidgetTester tester, ) async { - final ScrollController scrollController = ScrollController(); - addTearDown(scrollController.dispose); final Key leadingKey = GlobalKey(); final Key middleKey = GlobalKey(); final Key trailingKey = GlobalKey(); @@ -475,7 +473,6 @@ void main() { ), child: CupertinoPageScaffold( child: CustomScrollView( - controller: scrollController, slivers: [ CupertinoSliverNavigationBar( leading: Placeholder(key: leadingKey), @@ -797,6 +794,57 @@ void main() { expect(find.text('Home page'), findsOneWidget); }); + testWidgets('Navigation bars in a CupertinoSheetRoute have no back button', ( + WidgetTester tester, + ) async { + await tester.pumpWidget( + const CupertinoApp(home: CupertinoNavigationBar(middle: Text('Home page'))), + ); + + expect(find.byType(CupertinoButton), findsNothing); + + tester + .state(find.byType(Navigator)) + .push( + CupertinoSheetRoute( + builder: (BuildContext context) { + return const CupertinoPageScaffold( + navigationBar: CupertinoNavigationBar(middle: Text('Page 2')), + child: Placeholder(), + ); + }, + ), + ); + + await tester.pump(); + await tester.pump(const Duration(milliseconds: 600)); + + // No back button is found. + expect(find.byType(CupertinoButton), findsNothing); + expect(find.text(String.fromCharCode(CupertinoIcons.back.codePoint)), findsNothing); + + tester + .state(find.byType(Navigator)) + .push( + CupertinoSheetRoute( + builder: (BuildContext context) { + return const CupertinoPageScaffold( + child: CustomScrollView( + slivers: [CupertinoSliverNavigationBar(largeTitle: Text('Page 3'))], + ), + ); + }, + ), + ); + + await tester.pump(); + await tester.pump(const Duration(milliseconds: 600)); + + // No back button is found. + expect(find.byType(CupertinoButton), findsNothing); + expect(find.text(String.fromCharCode(CupertinoIcons.back.codePoint)), findsNothing); + }); + testWidgets('Long back label turns into "back"', (WidgetTester tester) async { await tester.pumpWidget(const CupertinoApp(home: Placeholder())); diff --git a/packages/flutter/test/cupertino/nav_bar_transition_test.dart b/packages/flutter/test/cupertino/nav_bar_transition_test.dart index 0d1ff01918..48d5e13aa1 100644 --- a/packages/flutter/test/cupertino/nav_bar_transition_test.dart +++ b/packages/flutter/test/cupertino/nav_bar_transition_test.dart @@ -343,6 +343,53 @@ void main() { expect(() => flying(tester, find.text('Page 2')), throwsAssertionError); }); + testWidgets('Navigation bars in a CupertinoSheetRoute have no hero transitions', ( + WidgetTester tester, + ) async { + await tester.pumpWidget( + CupertinoApp( + builder: (BuildContext context, Widget? navigator) { + return navigator!; + }, + home: const Placeholder(), + ), + ); + + tester + .state(find.byType(Navigator)) + .push( + CupertinoSheetRoute( + builder: + (BuildContext context) => + scaffoldForNavBar(const CupertinoNavigationBar(middle: Text('Page 1')))!, + ), + ); + + await tester.pump(); + await tester.pump(const Duration(milliseconds: 600)); + + tester + .state(find.byType(Navigator)) + .push( + CupertinoSheetRoute( + builder: + (BuildContext context) => + scaffoldForNavBar( + const CupertinoSliverNavigationBar(largeTitle: Text('Page 2')), + )!, + ), + ); + + await tester.pump(); + await tester.pump(const Duration(milliseconds: 50)); + + expect(find.byType(Hero), findsNothing); + + // No Hero transition happened. + expect(() => flying(tester, find.text('Page 1')), throwsAssertionError); + expect(() => flying(tester, find.text('Page 2')), throwsAssertionError); + }); + testWidgets('Popping mid-transition is symmetrical', (WidgetTester tester) async { await startTransitionBetween(tester, fromTitle: 'Page 1');