mirror of
https://github.com/flutter/flutter
synced 2024-10-13 19:52:53 +00:00
Customized Cupertino navigation bar. (#14307)
- Add override of border color of CupertinoNavigationBar - Add background color to CupertinoPageScaffold
This commit is contained in:
parent
e810bee6e5
commit
b88ba79c04
|
@ -79,7 +79,7 @@ class CupertinoIcons {
|
|||
/// A checkmark in a circle.
|
||||
static const IconData check_mark_circled = const IconData(0xf3fe, fontFamily: iconFont, fontPackage: iconFontPackage);
|
||||
|
||||
/// A thicker left chevron used in iOS for the nav bar back button.
|
||||
/// A thicker left chevron used in iOS for the navigation bar back button.
|
||||
static const IconData back = const IconData(0xf3cf, fontFamily: iconFont, fontPackage: iconFontPackage, matchTextDirection: true);
|
||||
|
||||
/// Outline of a simple front-facing house.
|
||||
|
|
|
@ -37,6 +37,14 @@ const Duration _kNavBarTitleFadeDuration = const Duration(milliseconds: 150);
|
|||
const Color _kDefaultNavBarBackgroundColor = const Color(0xCCF8F8F8);
|
||||
const Color _kDefaultNavBarBorderColor = const Color(0x4C000000);
|
||||
|
||||
const Border _kDefaultNavBarBorder = const Border(
|
||||
bottom: const BorderSide(
|
||||
color: _kDefaultNavBarBorderColor,
|
||||
width: 0.0, // One physical pixel.
|
||||
style: BorderStyle.solid,
|
||||
),
|
||||
);
|
||||
|
||||
const TextStyle _kLargeTitleTextStyle = const TextStyle(
|
||||
fontFamily: '.SF UI Text',
|
||||
fontSize: 34.0,
|
||||
|
@ -77,6 +85,7 @@ class CupertinoNavigationBar extends StatelessWidget implements ObstructingPrefe
|
|||
this.automaticallyImplyLeading: true,
|
||||
this.middle,
|
||||
this.trailing,
|
||||
this.border: _kDefaultNavBarBorder,
|
||||
this.backgroundColor: _kDefaultNavBarBackgroundColor,
|
||||
this.actionsForegroundColor: CupertinoColors.activeBlue,
|
||||
}) : assert(automaticallyImplyLeading != null),
|
||||
|
@ -109,6 +118,11 @@ class CupertinoNavigationBar extends StatelessWidget implements ObstructingPrefe
|
|||
/// behind it.
|
||||
final Color backgroundColor;
|
||||
|
||||
/// The border of the navigation bar. By default renders a single pixel bottom border side.
|
||||
///
|
||||
/// If a border is null, the navigation bar will not display a border.
|
||||
final Border border;
|
||||
|
||||
/// Default color used for text and icons of the [leading] and [trailing]
|
||||
/// widgets in the navigation bar.
|
||||
///
|
||||
|
@ -128,6 +142,7 @@ class CupertinoNavigationBar extends StatelessWidget implements ObstructingPrefe
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return _wrapWithBackground(
|
||||
border: border,
|
||||
backgroundColor: backgroundColor,
|
||||
child: new _CupertinoPersistentNavigationBar(
|
||||
leading: leading,
|
||||
|
@ -265,16 +280,14 @@ class CupertinoSliverNavigationBar extends StatelessWidget {
|
|||
|
||||
/// Returns `child` wrapped with background and a bottom border if background color
|
||||
/// is opaque. Otherwise, also blur with [BackdropFilter].
|
||||
Widget _wrapWithBackground({Color backgroundColor, Widget child}) {
|
||||
Widget _wrapWithBackground({
|
||||
Border border,
|
||||
Color backgroundColor,
|
||||
Widget child,
|
||||
}) {
|
||||
final DecoratedBox childWithBackground = new DecoratedBox(
|
||||
decoration: new BoxDecoration(
|
||||
border: const Border(
|
||||
bottom: const BorderSide(
|
||||
color: _kDefaultNavBarBorderColor,
|
||||
width: 0.0, // One physical pixel.
|
||||
style: BorderStyle.solid,
|
||||
),
|
||||
),
|
||||
border: border,
|
||||
color: backgroundColor,
|
||||
),
|
||||
child: child,
|
||||
|
@ -282,7 +295,8 @@ Widget _wrapWithBackground({Color backgroundColor, Widget child}) {
|
|||
|
||||
final bool darkBackground = backgroundColor.computeLuminance() < 0.179;
|
||||
SystemChrome.setSystemUIOverlayStyle(
|
||||
darkBackground ? SystemUiOverlayStyle.light : SystemUiOverlayStyle.dark);
|
||||
darkBackground ? SystemUiOverlayStyle.light : SystemUiOverlayStyle.dark
|
||||
);
|
||||
|
||||
if (backgroundColor.alpha == 0xFF)
|
||||
return childWithBackground;
|
||||
|
@ -424,7 +438,8 @@ class _CupertinoLargeTitleNavigationBarSliverDelegate
|
|||
this.automaticallyImplyLeading,
|
||||
this.middle,
|
||||
this.trailing,
|
||||
this.backgroundColor,
|
||||
this.border: _kDefaultNavBarBorder,
|
||||
this.backgroundColor: _kDefaultNavBarBackgroundColor,
|
||||
this.actionsForegroundColor,
|
||||
}) : assert(persistentHeight != null);
|
||||
|
||||
|
@ -442,6 +457,8 @@ class _CupertinoLargeTitleNavigationBarSliverDelegate
|
|||
|
||||
final Color backgroundColor;
|
||||
|
||||
final Border border;
|
||||
|
||||
final Color actionsForegroundColor;
|
||||
|
||||
@override
|
||||
|
@ -467,6 +484,7 @@ class _CupertinoLargeTitleNavigationBarSliverDelegate
|
|||
);
|
||||
|
||||
return _wrapWithBackground(
|
||||
border: border,
|
||||
backgroundColor: backgroundColor,
|
||||
child: new Stack(
|
||||
fit: StackFit.expand,
|
||||
|
|
|
@ -22,6 +22,7 @@ class CupertinoPageScaffold extends StatelessWidget {
|
|||
const CupertinoPageScaffold({
|
||||
Key key,
|
||||
this.navigationBar,
|
||||
this.backgroundColor: CupertinoColors.white,
|
||||
@required this.child,
|
||||
}) : assert(child != null),
|
||||
super(key: key);
|
||||
|
@ -32,7 +33,7 @@ class CupertinoPageScaffold extends StatelessWidget {
|
|||
/// If translucent, the main content may slide behind it.
|
||||
/// Otherwise, the main content's top margin will be offset by its height.
|
||||
///
|
||||
/// The scaffold assumes the nav bar will consume the [MediaQuery] top padding.
|
||||
/// The scaffold assumes the navigation bar will consume the [MediaQuery] top padding.
|
||||
// TODO(xster): document its page transition animation when ready
|
||||
final ObstructingPreferredSizeWidget navigationBar;
|
||||
|
||||
|
@ -44,6 +45,11 @@ class CupertinoPageScaffold extends StatelessWidget {
|
|||
/// [navigationBar].
|
||||
final Widget child;
|
||||
|
||||
/// The color of the widget that underlies the entire scaffold.
|
||||
///
|
||||
/// By default uses [CupertinoColors.white] color.
|
||||
final Color backgroundColor;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final List<Widget> stacked = <Widget>[];
|
||||
|
@ -57,8 +63,8 @@ class CupertinoPageScaffold extends StatelessWidget {
|
|||
final double topPadding = navigationBar.preferredSize.height
|
||||
+ existingMediaQuery.padding.top;
|
||||
|
||||
// If nav bar is opaquely obstructing, directly shift the main content
|
||||
// down. If translucent, let main content draw behind nav bar but hint the
|
||||
// If navigation bar is opaquely obstructing, directly shift the main content
|
||||
// down. If translucent, let main content draw behind navigation bar but hint the
|
||||
// obstructed area.
|
||||
if (navigationBar.fullObstruction) {
|
||||
paddedContent = new Padding(
|
||||
|
@ -90,7 +96,7 @@ class CupertinoPageScaffold extends StatelessWidget {
|
|||
}
|
||||
|
||||
return new DecoratedBox(
|
||||
decoration: const BoxDecoration(color: CupertinoColors.white),
|
||||
decoration: new BoxDecoration(color: backgroundColor),
|
||||
child: new Stack(
|
||||
children: stacked,
|
||||
),
|
||||
|
|
|
@ -395,6 +395,92 @@ void main() {
|
|||
|
||||
expect(find.text('Home page'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('Border should be displayed by default', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
new WidgetsApp(
|
||||
color: const Color(0xFFFFFFFF),
|
||||
onGenerateRoute: (RouteSettings settings) {
|
||||
return new CupertinoPageRoute<Null>(
|
||||
settings: settings,
|
||||
builder: (BuildContext context) {
|
||||
return const CupertinoNavigationBar(
|
||||
middle: const Text('Title'),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
final DecoratedBox decoratedBox = tester.widgetList(find.byType(DecoratedBox)).elementAt(1);
|
||||
expect(decoratedBox.decoration.runtimeType, BoxDecoration);
|
||||
|
||||
final BoxDecoration decoration = decoratedBox.decoration;
|
||||
expect(decoration.border, isNotNull);
|
||||
|
||||
final BorderSide side = decoration.border.bottom;
|
||||
expect(side, isNotNull);
|
||||
});
|
||||
|
||||
testWidgets('Overrides border color', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
new WidgetsApp(
|
||||
color: const Color(0xFFFFFFFF),
|
||||
onGenerateRoute: (RouteSettings settings) {
|
||||
return new CupertinoPageRoute<Null>(
|
||||
settings: settings,
|
||||
builder: (BuildContext context) {
|
||||
return const CupertinoNavigationBar(
|
||||
middle: const Text('Title'),
|
||||
border: const Border(
|
||||
bottom: const BorderSide(
|
||||
color: const Color(0xFFAABBCC),
|
||||
width: 0.0,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
final DecoratedBox decoratedBox = tester.widgetList(find.byType(DecoratedBox)).elementAt(1);
|
||||
expect(decoratedBox.decoration.runtimeType, BoxDecoration);
|
||||
|
||||
final BoxDecoration decoration = decoratedBox.decoration;
|
||||
expect(decoration.border, isNotNull);
|
||||
|
||||
final BorderSide side = decoration.border.bottom;
|
||||
expect(side, isNotNull);
|
||||
expect(side.color, const Color(0xFFAABBCC));
|
||||
});
|
||||
|
||||
testWidgets('Border should not be displayed when null', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
new WidgetsApp(
|
||||
color: const Color(0xFFFFFFFF),
|
||||
onGenerateRoute: (RouteSettings settings) {
|
||||
return new CupertinoPageRoute<Null>(
|
||||
settings: settings,
|
||||
builder: (BuildContext context) {
|
||||
return const CupertinoNavigationBar(
|
||||
middle: const Text('Title'),
|
||||
border: null,
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
final DecoratedBox decoratedBox = tester.widgetList(find.byType(DecoratedBox)).elementAt(1);
|
||||
expect(decoratedBox.decoration.runtimeType, BoxDecoration);
|
||||
|
||||
final BoxDecoration decoration = decoratedBox.decoration;
|
||||
expect(decoration.border, isNull);
|
||||
});
|
||||
}
|
||||
|
||||
class _ExpectStyles extends StatelessWidget {
|
||||
|
|
|
@ -254,4 +254,53 @@ void main() {
|
|||
expect(find.text('Page 1 of tab 2'), isOnstage);
|
||||
expect(find.text('Page 2 of tab 1', skipOffstage: false), isOffstage);
|
||||
});
|
||||
|
||||
testWidgets('Decorated with white background by default', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
new WidgetsApp(
|
||||
color: const Color(0xFFFFFFFF),
|
||||
onGenerateRoute: (RouteSettings settings) {
|
||||
return new CupertinoPageRoute<Null>(
|
||||
settings: settings,
|
||||
builder: (BuildContext context) {
|
||||
return const CupertinoPageScaffold(
|
||||
child: const Center(),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
final DecoratedBox decoratedBox = tester.widgetList(find.byType(DecoratedBox)).elementAt(1);
|
||||
expect(decoratedBox.decoration.runtimeType, BoxDecoration);
|
||||
|
||||
final BoxDecoration decoration = decoratedBox.decoration;
|
||||
expect(decoration.color, CupertinoColors.white);
|
||||
});
|
||||
|
||||
testWidgets('Overrides background color', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
new WidgetsApp(
|
||||
color: const Color(0xFFFFFFFF),
|
||||
onGenerateRoute: (RouteSettings settings) {
|
||||
return new CupertinoPageRoute<Null>(
|
||||
settings: settings,
|
||||
builder: (BuildContext context) {
|
||||
return const CupertinoPageScaffold(
|
||||
child: const Center(),
|
||||
backgroundColor: const Color(0xFF010203),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
final DecoratedBox decoratedBox = tester.widgetList(find.byType(DecoratedBox)).elementAt(1);
|
||||
expect(decoratedBox.decoration.runtimeType, BoxDecoration);
|
||||
|
||||
final BoxDecoration decoration = decoratedBox.decoration;
|
||||
expect(decoration.color, const Color(0xFF010203));
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue