mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
Update CupertinoNavigationBar to support large layout (#157133)
Fixes https://github.com/flutter/flutter/issues/149625 This adds a new constructor CupertinoNavigationBar.large for the large style navigation bar. CupertinoSliverNavigationBar enables dynamically changing between the smaller and larger layouts for native iOS headers in response to scrolling, this change makes it possible to configure the static navigation bar in one style or the other.
This commit is contained in:
parent
6337eb1a39
commit
2c20325af4
@ -0,0 +1,63 @@
|
||||
// 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 [CupertinoNavigationBar.large].
|
||||
|
||||
void main() => runApp(const NavBarApp());
|
||||
|
||||
class NavBarApp extends StatelessWidget {
|
||||
const NavBarApp({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return const CupertinoApp(
|
||||
theme: CupertinoThemeData(brightness: Brightness.light),
|
||||
home: NavBarExample(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class NavBarExample extends StatefulWidget {
|
||||
const NavBarExample({super.key});
|
||||
|
||||
@override
|
||||
State<NavBarExample> createState() => _NavBarExampleState();
|
||||
}
|
||||
|
||||
class _NavBarExampleState extends State<NavBarExample> {
|
||||
int _count = 0;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CupertinoPageScaffold(
|
||||
navigationBar: const CupertinoNavigationBar.large(
|
||||
largeTitle: Text('Large Sample'),
|
||||
),
|
||||
child: SafeArea(
|
||||
child: Center(
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
const Spacer(),
|
||||
const Text('You have pushed the button this many times:'),
|
||||
Text(
|
||||
'$_count',
|
||||
style: CupertinoTheme.of(context).textTheme.navLargeTitleTextStyle,
|
||||
),
|
||||
const Spacer(),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(15.0),
|
||||
child: CupertinoButton.filled(
|
||||
onPressed: () => setState(() => _count++),
|
||||
child: const Text('Increment'),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
// 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_navigation_bar.2.dart' as example;
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
void main() {
|
||||
testWidgets('CupertinoNavigationBar is large', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
const example.NavBarApp(),
|
||||
);
|
||||
|
||||
final Finder navBarFinder = find.byType(CupertinoNavigationBar);
|
||||
expect(navBarFinder, findsOneWidget);
|
||||
expect(find.text('Large Sample'), findsOneWidget);
|
||||
expect(find.text('0'), findsOneWidget);
|
||||
expect(find.text('1'), findsNothing);
|
||||
await tester.tap(find.text('Increment'));
|
||||
await tester.pump();
|
||||
expect(find.text('0'), findsNothing);
|
||||
expect(find.text('1'), findsOneWidget);
|
||||
});
|
||||
}
|
@ -219,26 +219,40 @@ bool _isTransitionable(BuildContext context) {
|
||||
|
||||
/// An iOS-styled navigation bar.
|
||||
///
|
||||
/// The navigation bar is a toolbar that minimally consists of a widget, normally
|
||||
/// a page title, in the [middle] of the toolbar.
|
||||
/// The navigation bar is a toolbar that minimally consists of a widget,
|
||||
/// normally a page title.
|
||||
///
|
||||
/// It also supports a [leading] and [trailing] widget before and after the
|
||||
/// [middle] widget while keeping the [middle] widget centered.
|
||||
/// It also supports [leading] and [trailing] widgets on either end of the
|
||||
/// toolbar, typically for actions and navigation.
|
||||
///
|
||||
/// The [leading] widget will automatically be a back chevron icon button (or a
|
||||
/// close button in case of a fullscreen dialog) to pop the current route if none
|
||||
/// is provided and [automaticallyImplyLeading] is true (true by default).
|
||||
///
|
||||
/// The [middle] widget will automatically be a title text from the current
|
||||
/// [CupertinoPageRoute] if none is provided and [automaticallyImplyMiddle] is
|
||||
/// true (true by default).
|
||||
///
|
||||
/// It should be placed at top of the screen and automatically accounts for
|
||||
/// the OS's status bar.
|
||||
/// This toolbar should be placed at top of the screen where it will
|
||||
/// automatically account for the OS's status bar.
|
||||
///
|
||||
/// If the given [backgroundColor]'s opacity is not 1.0 (which is the case by
|
||||
/// default), it will produce a blurring effect to the content behind it.
|
||||
///
|
||||
/// ### Layout options
|
||||
///
|
||||
/// While the [CupertinoSliverNavigationBar] can dynamically change size and
|
||||
/// layout in response to scrolling, this static version can reflect the same
|
||||
/// large (expanded) layout, or the small (collapsed) layout.
|
||||
///
|
||||
/// The default constructor will display the collapsed version of the
|
||||
/// [CupertinoSliverNavigationBar]. The [middle] widget will automatically be a
|
||||
/// title text from the current [CupertinoPageRoute] if none is provided and
|
||||
/// [automaticallyImplyMiddle] is true (true by default).
|
||||
///
|
||||
/// Using the [CupertinoNavigationBar.large] constructor will display the
|
||||
/// expanded version of [CupertinoSliverNavigationBar]. The [largeTitle] widget
|
||||
/// will automatically be a title text from the current [CupertinoPageRoute] if
|
||||
/// none is provided and `automaticallyImplyTitle` is true (true by default).
|
||||
///
|
||||
/// ### Transitions
|
||||
///
|
||||
/// When [transitionBetweenRoutes] is true, this navigation bar will transition
|
||||
/// on top of the routes instead of inside them if the route being transitioned
|
||||
/// to also has a [CupertinoNavigationBar] or a [CupertinoSliverNavigationBar]
|
||||
@ -264,6 +278,14 @@ bool _isTransitionable(BuildContext context) {
|
||||
/// ** See code in examples/api/lib/cupertino/nav_bar/cupertino_navigation_bar.0.dart **
|
||||
/// {@end-tool}
|
||||
///
|
||||
/// {@tool dartpad}
|
||||
/// This example shows the resulting layout from [CupertinoNavigationBar.large]
|
||||
/// constructor, showing a large title similar to the expanded state of
|
||||
/// [CupertinoSliverNavigationBar].
|
||||
///
|
||||
/// ** See code in examples/api/lib/cupertino/nav_bar/cupertino_navigation_bar.2.dart **
|
||||
/// {@end-tool}
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [CupertinoPageScaffold], a page layout helper typically hosting the
|
||||
@ -272,7 +294,16 @@ bool _isTransitionable(BuildContext context) {
|
||||
/// scrolling list and that supports iOS-11-style large titles.
|
||||
/// * <https://developer.apple.com/design/human-interface-guidelines/ios/bars/navigation-bars/>
|
||||
class CupertinoNavigationBar extends StatefulWidget implements ObstructingPreferredSizeWidget {
|
||||
/// Creates a navigation bar in the iOS style.
|
||||
/// Creates a static iOS style navigation bar, with a centered [middle] title.
|
||||
///
|
||||
/// Similar to the collapsed state of [CupertinoSliverNavigationBar], which
|
||||
/// can dynamically change size in response to scrolling.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [CupertinoNavigationBar.large], which creates a static iOS style
|
||||
/// navigation bar with a [largeTitle], similar to the expanded state of
|
||||
/// [CupertinoSliverNavigationBar].
|
||||
const CupertinoNavigationBar({
|
||||
super.key,
|
||||
this.leading,
|
||||
@ -290,12 +321,65 @@ class CupertinoNavigationBar extends StatefulWidget implements ObstructingPrefer
|
||||
this.transitionBetweenRoutes = true,
|
||||
this.heroTag = _defaultHeroTag,
|
||||
this.bottom,
|
||||
}) : assert(
|
||||
}) : largeTitle = null,
|
||||
assert(
|
||||
!transitionBetweenRoutes || identical(heroTag, _defaultHeroTag),
|
||||
'Cannot specify a heroTag override if this navigation bar does not '
|
||||
'transition due to transitionBetweenRoutes = false.',
|
||||
);
|
||||
|
||||
/// Creates a static iOS style navigation bar, with a left aligned [largeTitle].
|
||||
///
|
||||
/// Similar to the expanded state of [CupertinoSliverNavigationBar], which
|
||||
/// can dynamically change size in response to scrolling.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [CupertinoNavigationBar]'s base constructor, which creates a static
|
||||
/// iOS style navigation bar with [middle], similar to the collapsed state
|
||||
/// of [CupertinoSliverNavigationBar].
|
||||
const CupertinoNavigationBar.large({
|
||||
super.key,
|
||||
this.largeTitle,
|
||||
this.leading,
|
||||
this.automaticallyImplyLeading = true,
|
||||
bool automaticallyImplyTitle = true,
|
||||
this.previousPageTitle,
|
||||
this.trailing,
|
||||
this.border = _kDefaultNavBarBorder,
|
||||
this.backgroundColor,
|
||||
this.automaticBackgroundVisibility = true,
|
||||
this.enableBackgroundFilterBlur = true,
|
||||
this.brightness,
|
||||
this.padding,
|
||||
this.transitionBetweenRoutes = true,
|
||||
this.heroTag = _defaultHeroTag,
|
||||
this.bottom,
|
||||
}) : middle = null,
|
||||
automaticallyImplyMiddle = automaticallyImplyTitle,
|
||||
assert(
|
||||
!transitionBetweenRoutes || identical(heroTag, _defaultHeroTag),
|
||||
'Cannot specify a heroTag override if this navigation bar does not '
|
||||
'transition due to transitionBetweenRoutes = false.',
|
||||
);
|
||||
|
||||
/// The navigation bar's title, when using [CupertinoNavigationBar.large].
|
||||
///
|
||||
/// If null and `automaticallyImplyTitle` is true, an appropriate [Text]
|
||||
/// title will be created if the current route is a [CupertinoPageRoute] and
|
||||
/// has a `title`.
|
||||
///
|
||||
/// This property is null for the base [CupertinoNavigationBar] constructor,
|
||||
/// which shows a collapsed navigation bar and uses [middle] for the title
|
||||
/// instead.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [CupertinoSliverNavigationBar.largeTitle], a similar property
|
||||
/// in the expanded state of [CupertinoSliverNavigationBar], which can
|
||||
/// dynamically change size in response to scrolling.
|
||||
final Widget? largeTitle;
|
||||
|
||||
/// {@template flutter.cupertino.CupertinoNavigationBar.leading}
|
||||
/// Widget to place at the start of the navigation bar. Normally a back button
|
||||
/// for a normal page or a cancel button for full page dialogs.
|
||||
@ -342,12 +426,20 @@ class CupertinoNavigationBar extends StatefulWidget implements ObstructingPrefer
|
||||
/// {@endtemplate}
|
||||
final String? previousPageTitle;
|
||||
|
||||
/// Widget to place in the middle of the navigation bar. Normally a title or
|
||||
/// a segmented control.
|
||||
/// The navigation bar's default title.
|
||||
///
|
||||
/// If null and [automaticallyImplyMiddle] is true, an appropriate [Text]
|
||||
/// title will be created if the current route is a [CupertinoPageRoute] and
|
||||
/// has a `title`.
|
||||
///
|
||||
/// This property is null for the [CupertinoNavigationBar.large] constructor,
|
||||
/// which shows an expanded navigation bar and uses [largeTitle] instead.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [CupertinoSliverNavigationBar.middle], a similar property
|
||||
/// in the collapsed state of [CupertinoSliverNavigationBar], which can
|
||||
/// dynamically change size in response to scrolling.
|
||||
final Widget? middle;
|
||||
|
||||
/// {@template flutter.cupertino.CupertinoNavigationBar.trailing}
|
||||
@ -570,20 +662,32 @@ class _CupertinoNavigationBarState extends State<CupertinoNavigationBar> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final Color backgroundColor =
|
||||
CupertinoDynamicColor.maybeResolve(widget.backgroundColor, context) ?? CupertinoTheme.of(context).barBackgroundColor;
|
||||
// The static navigation bar does not expand or collapse (see CupertinoSliverNavigationBar),
|
||||
// it will either display the collapsed nav bar with middle, or the expanded with largeTitle.
|
||||
assert(widget.middle == null || widget.largeTitle == null);
|
||||
|
||||
final Color backgroundColor = CupertinoDynamicColor.maybeResolve(
|
||||
widget.backgroundColor,
|
||||
context,
|
||||
) ?? CupertinoTheme.of(context).barBackgroundColor;
|
||||
|
||||
final Color? parentPageScaffoldBackgroundColor = CupertinoPageScaffoldBackgroundColor.maybeOf(context);
|
||||
|
||||
final Border? initialBorder = widget.automaticBackgroundVisibility && parentPageScaffoldBackgroundColor != null
|
||||
? _kTransparentNavBarBorder
|
||||
: widget.border;
|
||||
final Border? effectiveBorder = widget.border == null ? null : Border.lerp(initialBorder, widget.border, _scrollAnimationValue,);
|
||||
final Border? effectiveBorder = widget.border == null
|
||||
? null
|
||||
: Border.lerp(initialBorder, widget.border, _scrollAnimationValue);
|
||||
|
||||
final Color effectiveBackgroundColor = widget.automaticBackgroundVisibility && parentPageScaffoldBackgroundColor != null
|
||||
? Color.lerp(parentPageScaffoldBackgroundColor, backgroundColor, _scrollAnimationValue) ?? backgroundColor
|
||||
: backgroundColor;
|
||||
|
||||
final double bottomHeight = widget.bottom?.preferredSize.height ?? 0.0;
|
||||
final double persistentHeight = _kNavBarPersistentHeight + bottomHeight + MediaQuery.paddingOf(context).top;
|
||||
final double largeHeight = persistentHeight + _kNavBarLargeTitleHeightExtension;
|
||||
|
||||
final _NavigationBarStaticComponents components = _NavigationBarStaticComponents(
|
||||
keys: keys,
|
||||
route: ModalRoute.of(context),
|
||||
@ -594,26 +698,69 @@ class _CupertinoNavigationBarState extends State<CupertinoNavigationBar> {
|
||||
userMiddle: widget.middle,
|
||||
userTrailing: widget.trailing,
|
||||
padding: widget.padding,
|
||||
userLargeTitle: null,
|
||||
large: false,
|
||||
userLargeTitle: widget.largeTitle,
|
||||
large: widget.largeTitle != null,
|
||||
staticBar: true, // This one does not scroll
|
||||
);
|
||||
|
||||
final Widget navBar = _wrapWithBackground(
|
||||
// Standard persistent components
|
||||
Widget navBar = _PersistentNavigationBar(
|
||||
components: components,
|
||||
padding: widget.padding,
|
||||
middleVisible: widget.largeTitle == null,
|
||||
);
|
||||
|
||||
if (widget.largeTitle != null) {
|
||||
// Large nav bar
|
||||
navBar = ConstrainedBox(
|
||||
constraints: BoxConstraints(maxHeight: largeHeight),
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
navBar,
|
||||
Expanded(
|
||||
child: Padding(
|
||||
padding: const EdgeInsetsDirectional.only(
|
||||
start: _kNavBarEdgePadding,
|
||||
bottom: _kNavBarBottomPadding
|
||||
),
|
||||
child: Semantics(
|
||||
header: true,
|
||||
child: DefaultTextStyle(
|
||||
style: CupertinoTheme.of(context)
|
||||
.textTheme
|
||||
.navLargeTitleTextStyle,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
child: _LargeTitle(child: components.largeTitle),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
if (widget.bottom != null) SizedBox(height: bottomHeight, child: widget.bottom),
|
||||
],
|
||||
),
|
||||
);
|
||||
} else {
|
||||
// Small nav bar
|
||||
navBar = ConstrainedBox(
|
||||
constraints: BoxConstraints(maxHeight: persistentHeight),
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
navBar,
|
||||
if (widget.bottom != null) SizedBox(height: bottomHeight, child: widget.bottom),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
navBar = _wrapWithBackground(
|
||||
border: effectiveBorder,
|
||||
backgroundColor: effectiveBackgroundColor,
|
||||
brightness: widget.brightness,
|
||||
enableBackgroundFilterBlur: widget.enableBackgroundFilterBlur,
|
||||
child: DefaultTextStyle(
|
||||
style: CupertinoTheme.of(context).textTheme.textStyle,
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
_PersistentNavigationBar(
|
||||
components: components,
|
||||
padding: widget.padding,
|
||||
),
|
||||
if (widget.bottom != null) widget.bottom!,
|
||||
],
|
||||
),
|
||||
child: navBar,
|
||||
),
|
||||
);
|
||||
|
||||
@ -638,10 +785,10 @@ class _CupertinoNavigationBarState extends State<CupertinoNavigationBar> {
|
||||
backgroundColor: effectiveBackgroundColor,
|
||||
backButtonTextStyle: CupertinoTheme.of(context).textTheme.navActionTextStyle,
|
||||
titleTextStyle: CupertinoTheme.of(context).textTheme.navTitleTextStyle,
|
||||
largeTitleTextStyle: null,
|
||||
largeTitleTextStyle: CupertinoTheme.of(context).textTheme.navLargeTitleTextStyle,
|
||||
border: effectiveBorder,
|
||||
hasUserMiddle: widget.middle != null,
|
||||
largeExpanded: false,
|
||||
largeExpanded: widget.largeTitle != null,
|
||||
child: navBar,
|
||||
),
|
||||
);
|
||||
@ -990,6 +1137,7 @@ class _CupertinoSliverNavigationBarState extends State<CupertinoSliverNavigation
|
||||
userLargeTitle: widget.largeTitle,
|
||||
padding: widget.padding,
|
||||
large: true,
|
||||
staticBar: false // This one scrolls.
|
||||
);
|
||||
|
||||
return MediaQuery.withNoTextScaling(
|
||||
@ -1489,6 +1637,7 @@ class _NavigationBarStaticComponents {
|
||||
required Widget? userLargeTitle,
|
||||
required EdgeInsetsDirectional? padding,
|
||||
required bool large,
|
||||
required bool staticBar,
|
||||
}) : leading = createLeading(
|
||||
leadingKey: keys.leadingKey,
|
||||
userLeading: userLeading,
|
||||
@ -1516,6 +1665,7 @@ class _NavigationBarStaticComponents {
|
||||
route: route,
|
||||
automaticallyImplyTitle: automaticallyImplyTitle,
|
||||
large: large,
|
||||
staticBar: staticBar,
|
||||
),
|
||||
trailing = createTrailing(
|
||||
trailingKey: keys.trailingKey,
|
||||
@ -1646,11 +1796,18 @@ class _NavigationBarStaticComponents {
|
||||
required Widget? userMiddle,
|
||||
required Widget? userLargeTitle,
|
||||
required bool large,
|
||||
required bool staticBar,
|
||||
required bool automaticallyImplyTitle,
|
||||
required ModalRoute<dynamic>? route,
|
||||
}) {
|
||||
Widget? middleContent = userMiddle;
|
||||
|
||||
if (large && staticBar) {
|
||||
// Static bar only displays the middle, or the large, not both.
|
||||
// A scrolling bar creates both middle and large to transition between.
|
||||
return null;
|
||||
}
|
||||
|
||||
if (large) {
|
||||
middleContent ??= userLargeTitle;
|
||||
}
|
||||
|
@ -34,6 +34,23 @@ void main() {
|
||||
expect(tester.getCenter(find.text('Title')).dx, 400.0);
|
||||
});
|
||||
|
||||
testWidgets('largeTitle is aligned with asymmetrical actions', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
const CupertinoApp(
|
||||
home: CupertinoNavigationBar.large(
|
||||
leading: CupertinoButton(
|
||||
onPressed: null,
|
||||
child: Text('Something'),
|
||||
),
|
||||
largeTitle: Text('Title'),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(tester.getCenter(find.text('Title')).dx, greaterThan(110.0));
|
||||
expect(tester.getCenter(find.text('Title')).dx, lessThan(111.0));
|
||||
});
|
||||
|
||||
testWidgets('Middle still in center with back button', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
const CupertinoApp(
|
||||
@ -58,6 +75,30 @@ void main() {
|
||||
expect(tester.getCenter(find.text('Page 2')).dx, 400.0);
|
||||
});
|
||||
|
||||
testWidgets('largeTitle still aligned with back button', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
const CupertinoApp(
|
||||
home: CupertinoNavigationBar.large(
|
||||
largeTitle: Text('Title'),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
tester.state<NavigatorState>(find.byType(Navigator)).push(CupertinoPageRoute<void>(
|
||||
builder: (BuildContext context) {
|
||||
return const CupertinoNavigationBar.large(
|
||||
largeTitle: Text('Page 2'),
|
||||
);
|
||||
},
|
||||
));
|
||||
|
||||
await tester.pump();
|
||||
await tester.pump(const Duration(milliseconds: 600));
|
||||
|
||||
expect(tester.getCenter(find.text('Page 2')).dx, greaterThan(129.0));
|
||||
expect(tester.getCenter(find.text('Page 2')).dx, lessThan(130.0));
|
||||
});
|
||||
|
||||
testWidgets('Opaque background does not add blur effects, non-opaque background adds blur effects', (WidgetTester tester) async {
|
||||
const CupertinoDynamicColor background = CupertinoDynamicColor.withBrightness(
|
||||
color: Color(0xFFE5E5E5),
|
||||
@ -1011,6 +1052,27 @@ void main() {
|
||||
semantics.dispose();
|
||||
});
|
||||
|
||||
testWidgets('Large CupertinoNavigationBar has semantics', (WidgetTester tester) async {
|
||||
final SemanticsTester semantics = SemanticsTester(tester);
|
||||
|
||||
await tester.pumpWidget(CupertinoApp(
|
||||
home: CupertinoPageScaffold(
|
||||
navigationBar: const CupertinoNavigationBar.large(
|
||||
largeTitle: Text('Fixed Title'),
|
||||
),
|
||||
child: Container(),
|
||||
),
|
||||
));
|
||||
|
||||
expect(semantics.nodesWith(
|
||||
label: 'Fixed Title',
|
||||
flags: <SemanticsFlag>[SemanticsFlag.isHeader],
|
||||
textDirection: TextDirection.ltr,
|
||||
), hasLength(1));
|
||||
|
||||
semantics.dispose();
|
||||
});
|
||||
|
||||
testWidgets('Border can be overridden in sliver nav bar', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
const CupertinoApp(
|
||||
@ -1050,59 +1112,96 @@ void main() {
|
||||
expect(bottom.color, const Color(0xFFAABBCC));
|
||||
});
|
||||
|
||||
testWidgets(
|
||||
'Standard title golden',
|
||||
(WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
const CupertinoApp(
|
||||
home: RepaintBoundary(
|
||||
child: CupertinoPageScaffold(
|
||||
navigationBar: CupertinoNavigationBar(
|
||||
testWidgets('Static standard title golden', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(const CupertinoApp(
|
||||
home: RepaintBoundary(
|
||||
child: CupertinoPageScaffold(
|
||||
navigationBar: CupertinoNavigationBar(
|
||||
middle: Text('Bling bling'),
|
||||
),
|
||||
child: Center(),
|
||||
),
|
||||
),
|
||||
));
|
||||
|
||||
await expectLater(
|
||||
find.byType(RepaintBoundary).last,
|
||||
matchesGoldenFile('nav_bar_test.standard_title.png'),
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('Static large title golden', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(const CupertinoApp(
|
||||
home: RepaintBoundary(
|
||||
child: CupertinoPageScaffold(
|
||||
navigationBar: CupertinoNavigationBar.large(
|
||||
largeTitle: Text('Bling bling'),
|
||||
),
|
||||
child: Center(),
|
||||
),
|
||||
),
|
||||
));
|
||||
|
||||
await expectLater(
|
||||
find.byType(RepaintBoundary).last,
|
||||
matchesGoldenFile('nav_bar_test.large_title.png'),
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('Sliver large title golden', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(CupertinoApp(
|
||||
home: RepaintBoundary(
|
||||
child: CupertinoPageScaffold(
|
||||
child: CustomScrollView(
|
||||
slivers: <Widget>[
|
||||
const CupertinoSliverNavigationBar(
|
||||
largeTitle: Text('Bling bling'),
|
||||
),
|
||||
SliverToBoxAdapter(
|
||||
child: Container(
|
||||
height: 1200.0,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
));
|
||||
|
||||
await expectLater(
|
||||
find.byType(RepaintBoundary).last,
|
||||
matchesGoldenFile('nav_bar_test.sliver.large_title.png'),
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('Sliver middle title golden', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(CupertinoApp(
|
||||
home: RepaintBoundary(
|
||||
child: CupertinoPageScaffold(
|
||||
child: CustomScrollView(
|
||||
slivers: <Widget>[
|
||||
const CupertinoSliverNavigationBar(
|
||||
middle: Text('Bling bling'),
|
||||
largeTitle: Text('Bling bling'),
|
||||
),
|
||||
child: Center(),
|
||||
),
|
||||
SliverToBoxAdapter(
|
||||
child: Container(
|
||||
height: 1200.0,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
),
|
||||
));
|
||||
await tester.drag(find.byType(Scrollable), const Offset(0.0, -250.0));
|
||||
await tester.pump();
|
||||
|
||||
await expectLater(
|
||||
find.byType(RepaintBoundary).last,
|
||||
matchesGoldenFile('nav_bar_test.standard_title.png'),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
testWidgets(
|
||||
'Large title golden',
|
||||
(WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
CupertinoApp(
|
||||
home: RepaintBoundary(
|
||||
child: CupertinoPageScaffold(
|
||||
child: CustomScrollView(
|
||||
slivers: <Widget>[
|
||||
const CupertinoSliverNavigationBar(
|
||||
largeTitle: Text('Bling bling'),
|
||||
),
|
||||
SliverToBoxAdapter(
|
||||
child: Container(
|
||||
height: 1200.0,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
await expectLater(
|
||||
find.byType(RepaintBoundary).last,
|
||||
matchesGoldenFile('nav_bar_test.large_title.png'),
|
||||
);
|
||||
},
|
||||
);
|
||||
await expectLater(
|
||||
find.byType(RepaintBoundary).last,
|
||||
matchesGoldenFile('nav_bar_test.sliver.middle_title.png'),
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets(
|
||||
'Nav bar background is transparent if `automaticBackgroundVisibility` is true and has no content scrolled under it',
|
||||
|
Loading…
Reference in New Issue
Block a user