Merge pull request #1907 from HansMuller/toolbar_bottom
Add support for "extended height" toolbars - ToolBar bottom Added a Widget-valued bottom ToolBar property. If set the bottom widget appears below the normal toolbar. Removed the kToolBarHeight hardwiring from Scaffold. Updated the "swipe away" demo to use an extended height toolbar.
This commit is contained in:
@@ -38,7 +38,7 @@ class CardCollectionState extends State<CardCollection> {
|
||||
List<CardModel> _cardModels;
|
||||
DismissDirection _dismissDirection = DismissDirection.horizontal;
|
||||
TextStyle _textStyle = new TextStyle(textAlign: TextAlign.center);
|
||||
bool _editable = true;
|
||||
bool _editable = false;
|
||||
bool _snapToCenter = false;
|
||||
bool _fixedSizeCards = false;
|
||||
bool _sunshine = false;
|
||||
@@ -268,10 +268,16 @@ class CardCollectionState extends State<CardCollection> {
|
||||
Widget buildToolBar() {
|
||||
return new ToolBar(
|
||||
left: new IconButton(icon: "navigation/menu", onPressed: _showDrawer),
|
||||
center: new Text('Swipe Away'),
|
||||
right: <Widget>[
|
||||
new Text(_dismissDirectionText(_dismissDirection))
|
||||
]
|
||||
],
|
||||
bottom: new Padding(
|
||||
padding: const EdgeDims.only(left: 72.0),
|
||||
child: new Align(
|
||||
alignment: const FractionalOffset(0.0, 0.5),
|
||||
child: new Text('Swipe Away: ${_cardModels.length}')
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ const double kStatusBarHeight = 50.0;
|
||||
// Mobile Portrait: 56dp
|
||||
// Tablet/Desktop: 64dp
|
||||
const double kToolBarHeight = 56.0;
|
||||
const double kExtendedToolBarHeight = 128.0;
|
||||
const double kSnackBarHeight = 52.0;
|
||||
|
||||
// https://www.google.com/design/spec/layout/metrics-keylines.html#metrics-keylines-keylines-spacing
|
||||
|
||||
@@ -218,18 +218,18 @@ class DropdownButton<T> extends StatelessComponent {
|
||||
return new GestureDetector(
|
||||
child: new Container(
|
||||
decoration: new BoxDecoration(border: _kDropdownUnderline),
|
||||
child: new IntrinsicWidth(
|
||||
child: new Row(<Widget>[
|
||||
new IndexedStack(items,
|
||||
key: indexedStackKey,
|
||||
index: selectedIndex,
|
||||
alignment: const FractionalOffset(0.5, 0.0)
|
||||
),
|
||||
new Container(
|
||||
child: new Icon(icon: 'navigation/arrow_drop_down', size: IconSize.s36),
|
||||
padding: const EdgeDims.only(top: 6.0)
|
||||
)
|
||||
])
|
||||
child: new Row(<Widget>[
|
||||
new IndexedStack(items,
|
||||
key: indexedStackKey,
|
||||
index: selectedIndex,
|
||||
alignment: const FractionalOffset(0.5, 0.0)
|
||||
),
|
||||
new Container(
|
||||
child: new Icon(icon: 'navigation/arrow_drop_down', size: IconSize.s36),
|
||||
padding: const EdgeDims.only(top: 6.0)
|
||||
)
|
||||
],
|
||||
justifyContent: FlexJustifyContent.collapse
|
||||
)
|
||||
),
|
||||
onTap: () {
|
||||
|
||||
@@ -4,92 +4,88 @@
|
||||
|
||||
import 'dart:ui' as ui;
|
||||
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
import 'constants.dart';
|
||||
import 'material.dart';
|
||||
import 'tool_bar.dart';
|
||||
|
||||
const int _kBodyIndex = 0;
|
||||
const int _kToolBarIndex = 1;
|
||||
|
||||
// This layout has the same effect as putting the toolbar and body in a column
|
||||
// and making the body flexible. What's different is that in this case the
|
||||
// toolbar appears -after- the body in the stacking order, so the toolbar's
|
||||
// shadow is drawn on top of the body.
|
||||
class _ToolBarAndBodyLayout extends MultiChildLayoutDelegate {
|
||||
void performLayout(Size size, BoxConstraints constraints, int childCount) {
|
||||
assert(childCount == 2);
|
||||
final BoxConstraints toolBarConstraints = constraints.loosen().tightenWidth(size.width);
|
||||
final Size toolBarSize = layoutChild(_kToolBarIndex, toolBarConstraints);
|
||||
final double bodyHeight = size.height - toolBarSize.height;
|
||||
final BoxConstraints bodyConstraints = toolBarConstraints.tightenHeight(bodyHeight);
|
||||
layoutChild(_kBodyIndex, bodyConstraints);
|
||||
positionChild(_kToolBarIndex, Point.origin);
|
||||
positionChild(_kBodyIndex, new Point(0.0, toolBarSize.height));
|
||||
}
|
||||
}
|
||||
|
||||
final _ToolBarAndBodyLayout _toolBarAndBodyLayout = new _ToolBarAndBodyLayout();
|
||||
|
||||
class Scaffold extends StatelessComponent {
|
||||
Scaffold({
|
||||
Key key,
|
||||
this.body,
|
||||
this.statusBar,
|
||||
this.toolBar,
|
||||
this.snackBar,
|
||||
this.floatingActionButton
|
||||
}) : super(key: key);
|
||||
|
||||
final Widget body;
|
||||
final Widget statusBar;
|
||||
final Widget toolBar;
|
||||
final ToolBar toolBar;
|
||||
final Widget snackBar;
|
||||
final Widget floatingActionButton;
|
||||
|
||||
Widget build(BuildContext context) {
|
||||
double toolBarHeight = 0.0;
|
||||
if (toolBar != null)
|
||||
toolBarHeight = kToolBarHeight + ui.window.padding.top;
|
||||
final ToolBar paddedToolBar = toolBar?.withPadding(new EdgeDims.only(top: ui.window.padding.top));
|
||||
final Widget materialBody = body != null ? new Material(child: body) : null;
|
||||
Widget toolBarAndBody;
|
||||
if (paddedToolBar != null && materialBody != null)
|
||||
toolBarAndBody = new CustomMultiChildLayout(<Widget>[materialBody, paddedToolBar],
|
||||
delegate: _toolBarAndBodyLayout
|
||||
);
|
||||
else
|
||||
toolBarAndBody = paddedToolBar ?? materialBody;
|
||||
|
||||
double statusBarHeight = 0.0;
|
||||
if (statusBar != null)
|
||||
statusBarHeight = kStatusBarHeight;
|
||||
final List<Widget> bottomColumnChildren = <Widget>[];
|
||||
|
||||
List<Widget> children = <Widget>[];
|
||||
if (floatingActionButton != null)
|
||||
bottomColumnChildren.add(new Padding(
|
||||
// TODO(eseidel): These change based on device size!
|
||||
padding: const EdgeDims.only(right: 16.0, bottom: 16.0),
|
||||
child: floatingActionButton
|
||||
));
|
||||
|
||||
if (body != null) {
|
||||
children.add(new Positioned(
|
||||
top: toolBarHeight, right: 0.0, bottom: statusBarHeight, left: 0.0,
|
||||
child: new Material(
|
||||
child: body
|
||||
)
|
||||
// TODO(jackson): On tablet/desktop, minWidth = 288, maxWidth = 568
|
||||
if (snackBar != null) {
|
||||
bottomColumnChildren.add(new ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxHeight: kSnackBarHeight),
|
||||
child: snackBar
|
||||
));
|
||||
}
|
||||
|
||||
if (statusBar != null) {
|
||||
children.add(new Positioned(
|
||||
right: 0.0, bottom: 0.0, left: 0.0,
|
||||
child: new SizedBox(
|
||||
height: statusBarHeight,
|
||||
child: statusBar
|
||||
)
|
||||
final List<Widget> stackChildren = <Widget>[toolBarAndBody];
|
||||
|
||||
if (bottomColumnChildren.length > 0) {
|
||||
stackChildren.add(new Positioned(
|
||||
right: 0.0,
|
||||
left: 0.0,
|
||||
bottom: 0.0,
|
||||
child: new Column(bottomColumnChildren, alignItems: FlexAlignItems.end)
|
||||
));
|
||||
}
|
||||
|
||||
if (toolBar != null) {
|
||||
children.add(new Positioned(
|
||||
top: 0.0, right: 0.0, left: 0.0,
|
||||
child: new SizedBox(
|
||||
height: toolBarHeight,
|
||||
child: toolBar
|
||||
)
|
||||
));
|
||||
}
|
||||
|
||||
if (snackBar != null || floatingActionButton != null) {
|
||||
List<Widget> floatingChildren = <Widget>[];
|
||||
|
||||
if (floatingActionButton != null) {
|
||||
floatingChildren.add(new Padding(
|
||||
// TODO(eseidel): These change based on device size!
|
||||
padding: const EdgeDims.only(right: 16.0, bottom: 16.0),
|
||||
child: floatingActionButton
|
||||
));
|
||||
}
|
||||
|
||||
// TODO(jackson): On tablet/desktop, minWidth = 288, maxWidth = 568
|
||||
if (snackBar != null) {
|
||||
floatingChildren.add(new ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxHeight: kSnackBarHeight),
|
||||
child: snackBar
|
||||
));
|
||||
}
|
||||
|
||||
children.add(new Positioned(
|
||||
right: 0.0, bottom: statusBarHeight, left: 0.0,
|
||||
child: new Column(floatingChildren, alignItems: FlexAlignItems.end)
|
||||
));
|
||||
}
|
||||
|
||||
return new Stack(children);
|
||||
return new Stack(stackChildren);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,17 +17,35 @@ class ToolBar extends StatelessComponent {
|
||||
this.left,
|
||||
this.center,
|
||||
this.right,
|
||||
this.bottom,
|
||||
this.level: 2,
|
||||
this.backgroundColor,
|
||||
this.textTheme
|
||||
this.textTheme,
|
||||
this.padding: EdgeDims.zero
|
||||
}) : super(key: key);
|
||||
|
||||
final Widget left;
|
||||
final Widget center;
|
||||
final List<Widget> right;
|
||||
final Widget bottom;
|
||||
final int level;
|
||||
final Color backgroundColor;
|
||||
final TextTheme textTheme;
|
||||
final EdgeDims padding;
|
||||
|
||||
ToolBar withPadding(EdgeDims newPadding) {
|
||||
return new ToolBar(
|
||||
key: key,
|
||||
left: left,
|
||||
center: center,
|
||||
right: right,
|
||||
bottom: bottom,
|
||||
level: level,
|
||||
backgroundColor: backgroundColor,
|
||||
textTheme: textTheme,
|
||||
padding: newPadding
|
||||
);
|
||||
}
|
||||
|
||||
Widget build(BuildContext context) {
|
||||
Color color = backgroundColor;
|
||||
@@ -62,6 +80,16 @@ class ToolBar extends StatelessComponent {
|
||||
if (right != null)
|
||||
children.addAll(right);
|
||||
|
||||
final List<Widget> columnChildren = <Widget>[
|
||||
new Container(height: kToolBarHeight, child: new Row(children))
|
||||
];
|
||||
|
||||
if (bottom != null)
|
||||
columnChildren.add(new DefaultTextStyle(
|
||||
style: centerStyle,
|
||||
child: new Container(height: kExtendedToolBarHeight - kToolBarHeight, child: bottom)
|
||||
));
|
||||
|
||||
Widget content = new AnimatedContainer(
|
||||
duration: kThemeChangeDuration,
|
||||
padding: new EdgeDims.symmetric(horizontal: 8.0),
|
||||
@@ -71,14 +99,7 @@ class ToolBar extends StatelessComponent {
|
||||
),
|
||||
child: new DefaultTextStyle(
|
||||
style: sideStyle,
|
||||
child: new Column(<Widget>[
|
||||
new Container(
|
||||
child: new Row(children),
|
||||
height: kToolBarHeight
|
||||
),
|
||||
],
|
||||
justifyContent: FlexJustifyContent.end
|
||||
)
|
||||
child: new Container(padding: padding, child: new Column(columnChildren, justifyContent: FlexJustifyContent.collapse))
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user