From 339f5500818dbc247a00ce2ab66cfd41461bba60 Mon Sep 17 00:00:00 2001 From: Ramon Farizel <45459898+RamonFarizel@users.noreply.github.com> Date: Wed, 30 Apr 2025 15:45:56 -0300 Subject: [PATCH] Update CupertinoSliverNavigationBar Docs (#167148) Update CupertinoSliverNavigationBar docs https://github.com/flutter/flutter/issues/164137 ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [x] I signed the [CLA]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [x] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md --------- Co-authored-by: Mitchell Goodwin <58190796+MitchellGoodwin@users.noreply.github.com> --- .../nav_bar/cupertino_sliver_nav_bar.2.dart | 112 ++++++++++++++++++ .../cupertino_sliver_nav_bar.2_test.dart | 86 ++++++++++++++ .../flutter/lib/src/cupertino/nav_bar.dart | 6 + 3 files changed, 204 insertions(+) create mode 100644 examples/api/lib/cupertino/nav_bar/cupertino_sliver_nav_bar.2.dart create mode 100644 examples/api/test/cupertino/nav_bar/cupertino_sliver_nav_bar.2_test.dart diff --git a/examples/api/lib/cupertino/nav_bar/cupertino_sliver_nav_bar.2.dart b/examples/api/lib/cupertino/nav_bar/cupertino_sliver_nav_bar.2.dart new file mode 100644 index 00000000000..5c3aa5e25ed --- /dev/null +++ b/examples/api/lib/cupertino/nav_bar/cupertino_sliver_nav_bar.2.dart @@ -0,0 +1,112 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/cupertino.dart'; + +/// Flutter code sample for [CupertinoSliverNavigationBar]. + +void main() => runApp(const SliverNavBarApp()); + +class SliverNavBarApp extends StatelessWidget { + const SliverNavBarApp({super.key}); + + @override + Widget build(BuildContext context) { + return const CupertinoApp( + theme: CupertinoThemeData(brightness: Brightness.light), + home: SliverNavBarExample(), + ); + } +} + +class SliverNavBarExample extends StatelessWidget { + const SliverNavBarExample({super.key}); + + @override + Widget build(BuildContext context) { + return CupertinoPageScaffold( + // A ScrollView that creates custom scroll effects using slivers. + child: CustomScrollView( + // A list of sliver widgets. + slivers: [ + const CupertinoSliverNavigationBar( + leading: Icon(CupertinoIcons.person_2), + // This title is visible in both collapsed and expanded states. + // When the "middle" parameter is omitted, the widget provided + // in the "largeTitle" parameter is used instead in the collapsed state. + largeTitle: Text('Contacts'), + bottom: PreferredSize( + preferredSize: Size.fromHeight(100), + child: ColoredBox(color: Color(0xff191970), child: Text('Bottom Widget')), + ), + trailing: Icon(CupertinoIcons.add_circled), + ), + // This widget fills the remaining space in the viewport. + // Drag the scrollable area to collapse the CupertinoSliverNavigationBar. + SliverFillRemaining( + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + const Text('Drag me up', textAlign: TextAlign.center), + CupertinoButton.filled( + onPressed: () { + Navigator.push( + context, + CupertinoPageRoute( + builder: (BuildContext context) { + return const NextPage(); + }, + ), + ); + }, + child: const Text('Go to Next Page'), + ), + ], + ), + ), + ], + ), + ); + } +} + +class NextPage extends StatelessWidget { + const NextPage({super.key}); + + @override + Widget build(BuildContext context) { + final Brightness brightness = CupertinoTheme.brightnessOf(context); + return CupertinoPageScaffold( + child: CustomScrollView( + slivers: [ + CupertinoSliverNavigationBar( + backgroundColor: CupertinoColors.systemYellow, + border: Border( + bottom: BorderSide( + color: + brightness == Brightness.light ? CupertinoColors.black : CupertinoColors.white, + ), + ), + // The middle widget is visible in both collapsed and expanded states. + middle: const Text('Contacts Group'), + // When the "middle" parameter is implemented, the largest title is only visible + // when the CupertinoSliverNavigationBar is fully expanded. + largeTitle: const Text('Family'), + ), + const SliverFillRemaining( + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Text('Drag me up', textAlign: TextAlign.center), + // When the "leading" parameter is omitted on a route that has a previous page, + // the back button is automatically added to the leading position. + Text('Tap on the leading button to navigate back', textAlign: TextAlign.center), + ], + ), + ), + ], + ), + ); + } +} 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 new file mode 100644 index 00000000000..3650887671a --- /dev/null +++ b/examples/api/test/cupertino/nav_bar/cupertino_sliver_nav_bar.2_test.dart @@ -0,0 +1,86 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/cupertino.dart'; +import 'package:flutter_api_samples/cupertino/nav_bar/cupertino_sliver_nav_bar.2.dart' as example; +import 'package:flutter_test/flutter_test.dart'; + +const Offset dragUp = Offset(0.0, -150.0); + +void main() { + testWidgets('CupertinoSliverNavigationBar bottom widget', (WidgetTester tester) async { + await tester.pumpWidget(const example.SliverNavBarApp()); + + final Finder preferredSize = find.byType(PreferredSize); + final Finder coloredBox = find.descendant(of: preferredSize, matching: find.byType(ColoredBox)); + final Finder text = find.text('Bottom Widget'); + + expect(preferredSize, findsOneWidget); + expect(coloredBox, findsOneWidget); + expect(text, findsOneWidget); + }); + + testWidgets('Collapse and expand CupertinoSliverNavigationBar changes title position', ( + WidgetTester tester, + ) async { + await tester.pumpWidget(const example.SliverNavBarApp()); + + // Large title is visible and at lower position. + expect(tester.getBottomLeft(find.text('Contacts').first).dy, 88.0); + await tester.fling(find.text('Drag me up'), dragUp, 500.0); + await tester.pumpAndSettle(); + + // Large title is hidden and at higher position. + expect( + tester.getBottomLeft(find.text('Contacts').first).dy, + 36.0 + 8.0, + ); // Static part + _kNavBarBottomPadding. + }); + + testWidgets('Middle widget is visible in both collapsed and expanded states', ( + WidgetTester tester, + ) async { + await tester.pumpWidget(const example.SliverNavBarApp()); + + // Navigate to a page that has both middle and large titles. + final Finder nextButton = find.text('Go to Next Page'); + expect(nextButton, findsOneWidget); + await tester.tap(nextButton); + await tester.pumpAndSettle(); + + // Both middle and large titles are visible. + expect(tester.getBottomLeft(find.text('Contacts Group').first).dy, 30.5); + expect(tester.getBottomLeft(find.text('Family').first).dy, 88.0); + + await tester.fling(find.text('Drag me up'), dragUp, 500.0); + await tester.pumpAndSettle(); + + // Large title is hidden and middle title is visible. + expect(tester.getBottomLeft(find.text('Contacts Group').first).dy, 30.5); + expect( + tester.getBottomLeft(find.text('Family').first).dy, + 36.0 + 8.0, + ); // Static part + _kNavBarBottomPadding. + }); + + testWidgets('CupertinoSliverNavigationBar with previous route has back button', ( + WidgetTester tester, + ) async { + await tester.pumpWidget(const example.SliverNavBarApp()); + + // Navigate to a page that has a back button. + final Finder nextButton = find.text('Go to Next Page'); + expect(nextButton, findsOneWidget); + await tester.tap(nextButton); + await tester.pumpAndSettle(); + expect(nextButton, findsNothing); + + // Go back to the previous page. + final Finder backButton = find.byType(CupertinoButton); + expect(backButton, findsOneWidget); + await tester.tap(backButton); + await tester.pumpAndSettle(); + expect(nextButton, findsOneWidget); + }); +} diff --git a/packages/flutter/lib/src/cupertino/nav_bar.dart b/packages/flutter/lib/src/cupertino/nav_bar.dart index 512e6108523..a5621121532 100644 --- a/packages/flutter/lib/src/cupertino/nav_bar.dart +++ b/packages/flutter/lib/src/cupertino/nav_bar.dart @@ -893,6 +893,12 @@ class _CupertinoNavigationBarState extends State { /// ** See code in examples/api/lib/cupertino/nav_bar/cupertino_sliver_nav_bar.0.dart ** /// {@end-tool} /// +/// {@tool dartpad} +/// To add a widget to the bottom of the nav bar, wrap it with [PreferredSize] and provide its fully extended size. +/// +/// ** See code in examples/api/lib/cupertino/nav_bar/cupertino_sliver_nav_bar.2.dart ** +/// {@end-tool} +/// /// See also: /// /// * [CupertinoNavigationBar], an iOS navigation bar for use on non-scrolling