diff --git a/dev/integration_tests/flutter_gallery/test/demo/cupertino/cupertino_navigation_demo_test.dart b/dev/integration_tests/flutter_gallery/test/demo/cupertino/cupertino_navigation_demo_test.dart index 2bd4049c8a4..3196ebcff30 100644 --- a/dev/integration_tests/flutter_gallery/test/demo/cupertino/cupertino_navigation_demo_test.dart +++ b/dev/integration_tests/flutter_gallery/test/demo/cupertino/cupertino_navigation_demo_test.dart @@ -12,6 +12,10 @@ void main() { // The point is to mainly test the cupertino icons that we don't have a // dependency against in the flutter/cupertino package directly. + // Set window orientation to portrait. + tester.view.physicalSize = const Size(2400.0, 3000.0); + addTearDown(tester.view.reset); + final Future font = rootBundle.load( 'packages/cupertino_icons/assets/CupertinoIcons.ttf', ); diff --git a/examples/api/test/cupertino/nav_bar/cupertino_sliver_nav_bar.0_test.dart b/examples/api/test/cupertino/nav_bar/cupertino_sliver_nav_bar.0_test.dart index 589a7a0d496..e31796241c1 100644 --- a/examples/api/test/cupertino/nav_bar/cupertino_sliver_nav_bar.0_test.dart +++ b/examples/api/test/cupertino/nav_bar/cupertino_sliver_nav_bar.0_test.dart @@ -8,10 +8,16 @@ import 'package:flutter_test/flutter_test.dart'; const Offset dragUp = Offset(0.0, -150.0); +void setWindowToPortrait(WidgetTester tester, {Size size = const Size(2400.0, 3000.0)}) { + tester.view.physicalSize = size; + addTearDown(tester.view.reset); +} + void main() { testWidgets('Collapse and expand CupertinoSliverNavigationBar changes title position', ( WidgetTester tester, ) async { + setWindowToPortrait(tester); await tester.pumpWidget(const example.SliverNavBarApp()); // Large title is visible and at lower position. @@ -29,6 +35,7 @@ void main() { testWidgets('Middle widget is visible in both collapsed and expanded states', ( WidgetTester tester, ) async { + setWindowToPortrait(tester); await tester.pumpWidget(const example.SliverNavBarApp()); // Navigate to a page that has both middle and large titles. @@ -55,6 +62,7 @@ void main() { testWidgets('CupertinoSliverNavigationBar with previous route has back button', ( WidgetTester tester, ) async { + setWindowToPortrait(tester); await tester.pumpWidget(const example.SliverNavBarApp()); // Navigate to a page that has back button diff --git a/examples/api/test/cupertino/nav_bar/cupertino_sliver_nav_bar.1_test.dart b/examples/api/test/cupertino/nav_bar/cupertino_sliver_nav_bar.1_test.dart index 25caf27d40a..e65a128a821 100644 --- a/examples/api/test/cupertino/nav_bar/cupertino_sliver_nav_bar.1_test.dart +++ b/examples/api/test/cupertino/nav_bar/cupertino_sliver_nav_bar.1_test.dart @@ -9,10 +9,16 @@ import 'package:flutter_test/flutter_test.dart'; const Offset titleDragUp = Offset(0.0, -100.0); const Offset bottomDragUp = Offset(0.0, -50.0); +void setWindowToPortrait(WidgetTester tester, {Size size = const Size(2400.0, 3000.0)}) { + tester.view.physicalSize = size; + addTearDown(tester.view.reset); +} + void main() { testWidgets('Collapse and expand CupertinoSliverNavigationBar changes title position', ( WidgetTester tester, ) async { + setWindowToPortrait(tester); await tester.pumpWidget(const example.SliverNavBarApp()); // Large title is visible and at lower position. @@ -28,6 +34,7 @@ void main() { }); testWidgets('Search field is hidden in bottom automatic mode', (WidgetTester tester) async { + setWindowToPortrait(tester); await tester.pumpWidget(const example.SliverNavBarApp()); // Navigate to a page with bottom automatic mode. @@ -64,6 +71,7 @@ void main() { }); testWidgets('Search field is always shown in bottom always mode', (WidgetTester tester) async { + setWindowToPortrait(tester); await tester.pumpWidget(const example.SliverNavBarApp()); // Navigate to a page with bottom always mode. @@ -92,6 +100,7 @@ void main() { }); testWidgets('Opens the search view when the search field is tapped', (WidgetTester tester) async { + setWindowToPortrait(tester); await tester.pumpWidget(const example.SliverNavBarApp()); // Navigate to a page with a search field. @@ -131,6 +140,7 @@ void main() { testWidgets('CupertinoSliverNavigationBar with previous route has back button', ( WidgetTester tester, ) async { + setWindowToPortrait(tester); await tester.pumpWidget(const example.SliverNavBarApp()); // Navigate to the first page. diff --git a/examples/api/test/cupertino/nav_bar/cupertino_sliver_nav_bar.2_test.dart b/examples/api/test/cupertino/nav_bar/cupertino_sliver_nav_bar.2_test.dart index 3650887671a..4477383a262 100644 --- a/examples/api/test/cupertino/nav_bar/cupertino_sliver_nav_bar.2_test.dart +++ b/examples/api/test/cupertino/nav_bar/cupertino_sliver_nav_bar.2_test.dart @@ -8,8 +8,14 @@ import 'package:flutter_test/flutter_test.dart'; const Offset dragUp = Offset(0.0, -150.0); +void setWindowToPortrait(WidgetTester tester, {Size size = const Size(2400.0, 3000.0)}) { + tester.view.physicalSize = size; + addTearDown(tester.view.reset); +} + void main() { testWidgets('CupertinoSliverNavigationBar bottom widget', (WidgetTester tester) async { + setWindowToPortrait(tester); await tester.pumpWidget(const example.SliverNavBarApp()); final Finder preferredSize = find.byType(PreferredSize); @@ -24,6 +30,7 @@ void main() { testWidgets('Collapse and expand CupertinoSliverNavigationBar changes title position', ( WidgetTester tester, ) async { + setWindowToPortrait(tester); await tester.pumpWidget(const example.SliverNavBarApp()); // Large title is visible and at lower position. @@ -41,6 +48,7 @@ void main() { testWidgets('Middle widget is visible in both collapsed and expanded states', ( WidgetTester tester, ) async { + setWindowToPortrait(tester); await tester.pumpWidget(const example.SliverNavBarApp()); // Navigate to a page that has both middle and large titles. @@ -67,6 +75,7 @@ void main() { testWidgets('CupertinoSliverNavigationBar with previous route has back button', ( WidgetTester tester, ) async { + setWindowToPortrait(tester); await tester.pumpWidget(const example.SliverNavBarApp()); // Navigate to a page that has a back button. diff --git a/packages/flutter/lib/src/cupertino/nav_bar.dart b/packages/flutter/lib/src/cupertino/nav_bar.dart index a5621121532..d71314d1ff8 100644 --- a/packages/flutter/lib/src/cupertino/nav_bar.dart +++ b/packages/flutter/lib/src/cupertino/nav_bar.dart @@ -1149,11 +1149,13 @@ class _CupertinoSliverNavigationBarState extends State persistentHeightAnimation; late Animation largeTitleHeightAnimation; bool searchIsActive = false; + bool isPortrait = true; @override void initState() { @@ -1169,6 +1171,14 @@ class _CupertinoSliverNavigationBarState extends State largeTitleHeightTween = Tween( + begin: isPortrait ? _kNavBarLargeTitleHeightExtension : 0.0, + end: 0.0, + ); + largeTitleHeightAnimation = largeTitleHeightTween.animate(_animationController); + effectiveMiddle = widget.middle ?? (isPortrait ? null : widget.largeTitle); + _scrollableState?.position.isScrollingNotifier.removeListener(_handleScrollChange); _scrollableState = Scrollable.maybeOf(context); _scrollableState?.position.isScrollingNotifier.addListener(_handleScrollChange); @@ -1203,11 +1213,6 @@ class _CupertinoSliverNavigationBarState extends State largeTitleHeightTween = Tween( - begin: _kNavBarLargeTitleHeightExtension, - end: 0.0, - ); - largeTitleHeightAnimation = largeTitleHeightTween.animate(_animationController); } void _handleScrollChange() { @@ -1221,16 +1226,17 @@ class _CupertinoSliverNavigationBarState extends State 0.0; + final double effectiveLargeTitleHeight = isPortrait ? _kNavBarLargeTitleHeightExtension : 0.0; // Snap the scroll view to a target determined by the navigation bar's // position. if (canScrollBottom && position.pixels < bottomScrollOffset) { target = position.pixels > bottomScrollOffset / 2 ? bottomScrollOffset : 0.0; } else if (position.pixels > bottomScrollOffset && - position.pixels < bottomScrollOffset + _kNavBarLargeTitleHeightExtension) { + position.pixels < bottomScrollOffset + effectiveLargeTitleHeight) { target = - position.pixels > bottomScrollOffset + (_kNavBarLargeTitleHeightExtension / 2) - ? bottomScrollOffset + _kNavBarLargeTitleHeightExtension + position.pixels > bottomScrollOffset + (effectiveLargeTitleHeight / 2) + ? bottomScrollOffset + effectiveLargeTitleHeight : bottomScrollOffset; } @@ -1280,7 +1286,7 @@ class _CupertinoSliverNavigationBarState extends State tester.binding.setSurfaceSize(null)); + setWindowToPortrait(tester); await tester.pumpWidget( const CupertinoApp( home: RepaintBoundary( @@ -2672,6 +2694,7 @@ void main() { }); testWidgets('onSearchableBottomTap callback', (WidgetTester tester) async { + setWindowToPortrait(tester); const Color activeSearchColor = Color(0x0000000A); const Color inactiveSearchColor = Color(0x0000000B); bool isSearchActive = false; @@ -2750,6 +2773,7 @@ void main() { testWidgets( 'CupertinoSliverNavigationBar.search large title and cancel buttons fade during search animation', (WidgetTester tester) async { + setWindowToPortrait(tester); await tester.pumpWidget( const CupertinoApp( home: CustomScrollView( @@ -2826,6 +2850,52 @@ void main() { expect(cancelOpacity.opacity.value, 0.0); }, ); + + testWidgets('Large title is hidden if middle is provided in landscape mode', ( + WidgetTester tester, + ) async { + const String largeTitle = 'Large title'; + const String middle = 'Middle'; + await tester.pumpWidget( + const CupertinoApp( + home: CustomScrollView( + slivers: [ + CupertinoSliverNavigationBar.search( + largeTitle: Text(largeTitle), + middle: Text(middle), + searchField: CupertinoSearchTextField(), + ), + SliverFillRemaining(child: SizedBox(height: 1000.0)), + ], + ), + ), + ); + + expect(find.text(largeTitle), findsNothing); + expect(find.text(middle), findsOneWidget); + expect(find.byType(CupertinoSearchTextField), findsOneWidget); + }); + + testWidgets('Large title is shown in middle position in landscape mode', ( + WidgetTester tester, + ) async { + const String largeTitle = 'Large title'; + await tester.pumpWidget( + const CupertinoApp( + home: CustomScrollView( + slivers: [ + CupertinoSliverNavigationBar.search( + largeTitle: Text(largeTitle), + searchField: CupertinoSearchTextField(), + ), + SliverFillRemaining(child: SizedBox(height: 1000.0)), + ], + ), + ), + ); + expect(find.text(largeTitle), findsOneWidget); + expect(find.byType(CupertinoSearchTextField), findsOneWidget); + }); } class _ExpectStyles extends StatelessWidget { diff --git a/packages/flutter/test/cupertino/nav_bar_transition_test.dart b/packages/flutter/test/cupertino/nav_bar_transition_test.dart index 97c67dda8b0..cb79d112d2f 100644 --- a/packages/flutter/test/cupertino/nav_bar_transition_test.dart +++ b/packages/flutter/test/cupertino/nav_bar_transition_test.dart @@ -132,6 +132,11 @@ void checkOpacity(WidgetTester tester, Finder finder, double opacity) { ); } +void setWindowToPortrait(WidgetTester tester, {Size size = const Size(2400.0, 3000.0)}) { + tester.view.physicalSize = size; + addTearDown(tester.view.reset); +} + void main() { testWidgets('Bottom middle moves between middle and back label', (WidgetTester tester) async { await startTransitionBetween(tester, fromTitle: 'Page 1'); @@ -666,6 +671,7 @@ void main() { testWidgets('Middle is not shown if alwaysShowMiddle is false and the nav bar is expanded', ( WidgetTester tester, ) async { + setWindowToPortrait(tester); const Widget userMiddle = Placeholder(); await startTransitionBetween( tester, @@ -987,6 +993,7 @@ void main() { }); testWidgets('Bottom large title moves to top back label', (WidgetTester tester) async { + setWindowToPortrait(tester); await startTransitionBetween( tester, from: const CupertinoSliverNavigationBar(), @@ -1045,6 +1052,7 @@ void main() { testWidgets('Bottom CupertinoSliverNavigationBar.bottom fades and slides out from the left', ( WidgetTester tester, ) async { + setWindowToPortrait(tester); await startTransitionBetween( tester, from: const CupertinoSliverNavigationBar( @@ -1081,6 +1089,7 @@ void main() { testWidgets('Bottom CupertinoNavigationBar.bottom fades and slides out from the left', ( WidgetTester tester, ) async { + setWindowToPortrait(tester); await startTransitionBetween( tester, from: const CupertinoNavigationBar( @@ -1117,6 +1126,7 @@ void main() { testWidgets( 'CupertinoSliverNavigationBar.bottom clips its contents mid-transition when scrolled', (WidgetTester tester) async { + setWindowToPortrait(tester); await tester.pumpWidget( CupertinoApp( builder: (BuildContext context, Widget? navigator) { @@ -1233,6 +1243,7 @@ void main() { ); testWidgets('Long title turns into the word back mid transition', (WidgetTester tester) async { + setWindowToPortrait(tester); await startTransitionBetween( tester, from: const CupertinoSliverNavigationBar(), @@ -1289,6 +1300,7 @@ void main() { testWidgets('Bottom large title and top back label transitions their font', ( WidgetTester tester, ) async { + setWindowToPortrait(tester); await startTransitionBetween( tester, from: const CupertinoSliverNavigationBar(), @@ -1397,6 +1409,7 @@ void main() { }); testWidgets('Top large title fades in and slides in from the right', (WidgetTester tester) async { + setWindowToPortrait(tester); await startTransitionBetween( tester, to: const CupertinoSliverNavigationBar(), @@ -1427,6 +1440,7 @@ void main() { testWidgets('Top large title fades in and slides in from the left in RTL', ( WidgetTester tester, ) async { + setWindowToPortrait(tester); await startTransitionBetween( tester, to: const CupertinoSliverNavigationBar(), @@ -1460,6 +1474,7 @@ void main() { ) async { const double horizontalPadding = 16.0; // _kNavBarEdgePadding const double height = 30.0; + setWindowToPortrait(tester); await startTransitionBetween( tester, toTitle: 'Page 2', @@ -1503,7 +1518,7 @@ void main() { // The nav bar bottom is horizontally aligned to the large title. expect( tester.getTopLeft(flying(tester, find.byType(Placeholder))).dx, - largeTitleOffset.dx - horizontalPadding, + moreOrLessEquals(largeTitleOffset.dx - horizontalPadding, epsilon: 0.01), ); }); @@ -1581,6 +1596,7 @@ void main() { ) async { int bottomBuildTimes = 0; int topBuildTimes = 0; + setWindowToPortrait(tester); await startTransitionBetween( tester, from: CupertinoNavigationBar( diff --git a/packages/flutter/test/cupertino/route_test.dart b/packages/flutter/test/cupertino/route_test.dart index 534fcd9da02..520d540714f 100644 --- a/packages/flutter/test/cupertino/route_test.dart +++ b/packages/flutter/test/cupertino/route_test.dart @@ -51,6 +51,9 @@ void main() { }); testWidgets('Large title auto-populates with title', (WidgetTester tester) async { + // Set window orientation to portrait. + tester.view.physicalSize = const Size(2400.0, 3000.0); + addTearDown(tester.view.reset); await tester.pumpWidget(const CupertinoApp(home: Placeholder())); tester