Commit 2aaa7f88 authored by xster's avatar xster Committed by GitHub

CupertinoNavigationBar part 2 - create a bare bone CupertinoNavigationBar (#10423)

Create a CupertinoNavigationBar without automatic adding of the lead button
parent a8777ce6
......@@ -12,6 +12,7 @@ export 'src/cupertino/bottom_tab_bar.dart';
export 'src/cupertino/button.dart';
export 'src/cupertino/colors.dart';
export 'src/cupertino/dialog.dart';
export 'src/cupertino/nav_bar.dart';
export 'src/cupertino/page.dart';
export 'src/cupertino/slider.dart';
export 'src/cupertino/switch.dart';
......
......@@ -13,7 +13,24 @@ import 'colors.dart';
const double _kTabBarHeight = 50.0;
const Color _kDefaultTabBarBackgroundColor = const Color(0xCCF8F8F8);
const Color _kDefaultTabBarBorderColor = const Color(0x4C000000);
/// An iOS styled bottom navigation tab bar.
///
/// Displays multiple tabs using [BottomNavigationBarItem] with one tab being
/// active, the first tab by default.
///
/// This [StatelessWidget] doesn't store the active tab itself. You must
/// listen to the [onTap] callbacks and call `setState` with a new [currentIndex]
/// for the new selection to reflect.
///
/// Tab changes typically trigger a switch between [Navigator]s, each with its
/// own navigation stack, per standard iOS design.
///
/// 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.
///
// TODO(xster): document using with a CupertinoScaffold.
class CupertinoTabBar extends StatelessWidget {
CupertinoTabBar({
Key key,
......@@ -72,7 +89,7 @@ class CupertinoTabBar extends StatelessWidget {
decoration: new BoxDecoration(
border: const Border(
top: const BorderSide(
color: const Color(0x4C000000),
color: _kDefaultTabBarBorderColor,
width: 0.0, // One physical pixel.
style: BorderStyle.solid,
),
......
// Copyright 2017 The Chromium 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 'dart:ui' show ImageFilter;
import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';
import 'colors.dart';
// Standard iOS 10 nav bar height without the status bar.
const double _kNavBarHeight = 44.0;
const Color _kDefaultNavBarBackgroundColor = const Color(0xCCF8F8F8);
const Color _kDefaultNavBarBorderColor = const Color(0x4C000000);
/// 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.
///
/// It also supports a [leading] and [trailing] widget before and after the
/// [middle] widget while keeping the [middle] widget centered.
///
/// It should be placed at top of the screen and automatically accounts 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.
///
// TODO(xster): document automatic addition of a CupertinoBackButton.
// TODO(xster): add sample code using icons.
// TODO(xster): document integration into a CupertinoScaffold.
class CupertinoNavigationBar extends StatelessWidget implements PreferredSizeWidget {
const CupertinoNavigationBar({
Key key,
this.leading,
@required this.middle,
this.trailing,
this.backgroundColor: _kDefaultNavBarBackgroundColor,
this.actionsForegroundColor: CupertinoColors.activeBlue,
}) : assert(middle != null, 'There must be a middle widget, usually a title'),
super(key: key);
/// Widget to place at the start of the nav bar. Normally a back button
/// for a normal page or a cancel button for full page dialogs.
final Widget leading;
/// Widget to place in the middle of the nav bar. Normally a title or
/// a segmented control.
final Widget middle;
/// Widget to place at the end of the nav bar. Normally additional actions
/// taken on the page such as a search or edit function.
final Widget trailing;
// TODO(xster): implement support for double row nav bars.
/// The background color of the nav bar. If it contains transparency, the
/// tab bar will automatically produce a blurring effect to the content
/// behind it.
final Color backgroundColor;
/// Default color used for text and icons of the [leading] and [trailing]
/// widgets in the nav bar.
///
/// The [title] remains black if it's a text as per iOS standard design.
final Color actionsForegroundColor;
@override
Size get preferredSize => const Size.fromHeight(_kNavBarHeight);
@override
Widget build(BuildContext context) {
final bool addBlur = backgroundColor.alpha != 0xFF;
Widget styledMiddle = middle;
if (styledMiddle.runtimeType == Text || styledMiddle.runtimeType == DefaultTextStyle) {
// Let the middle be black rather than `actionsForegroundColor` in case
// it's a plain text title.
styledMiddle = DefaultTextStyle.merge(
style: const TextStyle(color: CupertinoColors.black),
child: middle,
);
}
// TODO(xster): automatically build a CupertinoBackButton.
Widget result = new DecoratedBox(
decoration: new BoxDecoration(
border: const Border(
bottom: const BorderSide(
color: _kDefaultNavBarBorderColor,
width: 0.0, // One physical pixel.
style: BorderStyle.solid,
),
),
color: backgroundColor,
),
child: new SizedBox(
height: _kNavBarHeight + MediaQuery.of(context).padding.top,
child: IconTheme.merge(
data: new IconThemeData(
color: actionsForegroundColor,
size: 22.0,
),
child: DefaultTextStyle.merge(
style: new TextStyle(
fontSize: 17.0,
letterSpacing: -0.24,
color: actionsForegroundColor,
),
child: new Padding(
padding: new EdgeInsets.only(
top: MediaQuery.of(context).padding.top,
// TODO(xster): dynamically reduce padding when an automatic
// CupertinoBackButton is present.
left: 16.0,
right: 16.0,
),
child: new NavigationToolbar(
leading: leading,
middle: styledMiddle,
trailing: trailing,
centerMiddle: true,
),
),
),
),
),
);
if (addBlur) {
// For non-opaque backgrounds, apply a blur effect.
result = new ClipRect(
child: new BackdropFilter(
filter: new ImageFilter.blur(sigmaX: 10.0, sigmaY: 10.0),
child: result,
),
);
}
return result;
}
}
// Copyright 2017 The Chromium 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/rendering.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
testWidgets('Middle still in center with asymmetrical actions', (WidgetTester tester) async {
await tester.pumpWidget(
new WidgetsApp(
color: const Color(0xFFFFFFFF),
onGenerateRoute: (RouteSettings settings) {
return new PageRouteBuilder<Null>(
settings: settings,
pageBuilder: (BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation) {
return const CupertinoNavigationBar(
leading: const CupertinoButton(child: const Text('Something'), onPressed: null,),
middle: const Text('Title'),
);
},
);
},
),
);
// Expect the middle of the title to be exactly in the middle of the screen.
expect(tester.getCenter(find.text('Title')).dx, 400.0);
});
testWidgets('Opaque background does not add blur effects', (WidgetTester tester) async {
await tester.pumpWidget(
new WidgetsApp(
color: const Color(0xFFFFFFFF),
onGenerateRoute: (RouteSettings settings) {
return new PageRouteBuilder<Null>(
settings: settings,
pageBuilder: (BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation) {
return const CupertinoNavigationBar(
middle: const Text('Title'),
backgroundColor: const Color(0xFFE5E5E5),
);
},
);
},
),
);
expect(find.byType(BackdropFilter), findsNothing);
});
testWidgets('Non-opaque background adds blur effects', (WidgetTester tester) async {
await tester.pumpWidget(
new WidgetsApp(
color: const Color(0xFFFFFFFF),
onGenerateRoute: (RouteSettings settings) {
return new PageRouteBuilder<Null>(
settings: settings,
pageBuilder: (BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation) {
return const CupertinoNavigationBar(
middle: const Text('Title'),
);
},
);
},
),
);
expect(find.byType(BackdropFilter), findsOneWidget);
});
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment