Commit d10c5628 authored by Adam Barth's avatar Adam Barth

Merge pull request #1330 from abarth/bottom_padding

Scaffold should respect window.padding.bottom
parents 073ac691 da7e1e5d
......@@ -68,17 +68,24 @@ class MaterialApp extends StatefulComponent {
_MaterialAppState createState() => new _MaterialAppState();
}
EdgeDims _getPadding(ui.Window window) {
ui.WindowPadding padding = ui.window.padding;
return new EdgeDims.TRBL(padding.top, padding.right, padding.bottom, padding.left);
}
class _MaterialAppState extends State<MaterialApp> implements BindingObserver {
GlobalObjectKey _navigator;
Size _size;
EdgeDims _padding;
LocaleQueryData _localeData;
void initState() {
super.initState();
_navigator = new GlobalObjectKey(this);
_size = ui.window.size;
_padding = _getPadding(ui.window);
didChangeLocale(ui.window.locale);
WidgetFlutterBinding.instance.addObserver(this);
}
......@@ -99,7 +106,12 @@ class _MaterialAppState extends State<MaterialApp> implements BindingObserver {
return result;
}
void didChangeSize(Size size) => setState(() { _size = size; });
void didChangeSize(Size size) {
setState(() {
_size = size;
_padding = _getPadding(ui.window);
});
}
void didChangeLocale(ui.Locale locale) {
if (config.onLocaleChanged != null) {
......@@ -138,7 +150,7 @@ class _MaterialAppState extends State<MaterialApp> implements BindingObserver {
ThemeData theme = config.theme ?? new ThemeData.fallback();
Widget result = new MediaQuery(
data: new MediaQueryData(size: _size),
data: new MediaQueryData(size: _size, padding: _padding),
child: new LocaleQuery(
data: _localeData,
child: new AnimatedTheme(
......
......@@ -5,18 +5,17 @@
import 'dart:async';
import 'dart:collection';
import 'dart:math' as math;
import 'dart:ui' as ui;
import 'package:flutter/animation.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';
import 'bottom_sheet.dart';
import 'drawer.dart';
import 'icon_button.dart';
import 'material.dart';
import 'snack_bar.dart';
import 'tool_bar.dart';
import 'drawer.dart';
import 'icon_button.dart';
const double _kFloatingActionButtonMargin = 16.0; // TODO(hmuller): should be device dependent
const Duration _kFloatingActionButtonSegue = const Duration(milliseconds: 400);
......@@ -31,6 +30,10 @@ enum _ScaffoldSlot {
}
class _ScaffoldLayout extends MultiChildLayoutDelegate {
_ScaffoldLayout({ this.padding });
final EdgeDims padding;
void performLayout(Size size, BoxConstraints constraints) {
BoxConstraints looseConstraints = constraints.loosen();
......@@ -41,18 +44,19 @@ class _ScaffoldLayout extends MultiChildLayoutDelegate {
// so the toolbar's shadow is drawn on top of the body.
final BoxConstraints fullWidthConstraints = looseConstraints.tighten(width: size.width);
Size toolBarSize = Size.zero;
double contentTop = padding.top;
double contentBottom = size.height - padding.bottom;
if (isChild(_ScaffoldSlot.toolBar)) {
toolBarSize = layoutChild(_ScaffoldSlot.toolBar, fullWidthConstraints);
contentTop = layoutChild(_ScaffoldSlot.toolBar, fullWidthConstraints).height;
positionChild(_ScaffoldSlot.toolBar, Offset.zero);
}
if (isChild(_ScaffoldSlot.body)) {
final double bodyHeight = size.height - toolBarSize.height;
final double bodyHeight = contentBottom - contentTop;
final BoxConstraints bodyConstraints = fullWidthConstraints.tighten(height: bodyHeight);
layoutChild(_ScaffoldSlot.body, bodyConstraints);
positionChild(_ScaffoldSlot.body, new Offset(0.0, toolBarSize.height));
positionChild(_ScaffoldSlot.body, new Offset(0.0, contentTop));
}
// The BottomSheet and the SnackBar are anchored to the bottom of the parent,
......@@ -69,22 +73,22 @@ class _ScaffoldLayout extends MultiChildLayoutDelegate {
if (isChild(_ScaffoldSlot.bottomSheet)) {
bottomSheetSize = layoutChild(_ScaffoldSlot.bottomSheet, fullWidthConstraints);
positionChild(_ScaffoldSlot.bottomSheet, new Offset((size.width - bottomSheetSize.width) / 2.0, size.height - bottomSheetSize.height));
positionChild(_ScaffoldSlot.bottomSheet, new Offset((size.width - bottomSheetSize.width) / 2.0, contentBottom - bottomSheetSize.height));
}
if (isChild(_ScaffoldSlot.snackBar)) {
snackBarSize = layoutChild(_ScaffoldSlot.snackBar, fullWidthConstraints);
positionChild(_ScaffoldSlot.snackBar, new Offset(0.0, size.height - snackBarSize.height));
positionChild(_ScaffoldSlot.snackBar, new Offset(0.0, contentBottom - snackBarSize.height));
}
if (isChild(_ScaffoldSlot.floatingActionButton)) {
final Size fabSize = layoutChild(_ScaffoldSlot.floatingActionButton, looseConstraints);
final double fabX = size.width - fabSize.width - _kFloatingActionButtonMargin;
double fabY = size.height - fabSize.height - _kFloatingActionButtonMargin;
double fabY = contentBottom - fabSize.height - _kFloatingActionButtonMargin;
if (snackBarSize.height > 0.0)
fabY = math.min(fabY, size.height - snackBarSize.height - fabSize.height - _kFloatingActionButtonMargin);
fabY = math.min(fabY, contentBottom - snackBarSize.height - fabSize.height - _kFloatingActionButtonMargin);
if (bottomSheetSize.height > 0.0)
fabY = math.min(fabY, size.height - bottomSheetSize.height - fabSize.height / 2.0);
fabY = math.min(fabY, contentBottom - bottomSheetSize.height - fabSize.height / 2.0);
positionChild(_ScaffoldSlot.floatingActionButton, new Offset(fabX, fabY));
}
......@@ -94,7 +98,9 @@ class _ScaffoldLayout extends MultiChildLayoutDelegate {
}
}
bool shouldRelayout(MultiChildLayoutDelegate oldDelegate) => false;
bool shouldRelayout(_ScaffoldLayout oldDelegate) {
return padding != oldDelegate.padding;
}
}
class _FloatingActionButtonTransition extends StatefulComponent {
......@@ -329,11 +335,11 @@ class ScaffoldState extends State<Scaffold> {
bool _shouldShowBackArrow;
Widget get _modifiedToolBar {
Widget _getModifiedToolBar(EdgeDims padding) {
ToolBar toolBar = config.toolBar;
if (toolBar == null)
return null;
EdgeDims padding = new EdgeDims.only(top: ui.window.padding.top);
EdgeDims toolBarPadding = new EdgeDims.only(top: padding.top);
Widget left = toolBar.left;
if (left == null) {
if (config.drawer != null) {
......@@ -354,13 +360,13 @@ class ScaffoldState extends State<Scaffold> {
}
}
return toolBar.copyWith(
padding: padding,
padding: toolBarPadding,
left: left
);
}
Widget build(BuildContext context) {
final Widget materialBody = config.body != null ? new Material(child: config.body) : null;
EdgeDims padding = MediaQuery.of(context).padding;
if (_snackBars.length > 0) {
ModalRoute route = ModalRoute.of(context);
......@@ -373,9 +379,9 @@ class ScaffoldState extends State<Scaffold> {
}
}
final List<LayoutId>children = new List<LayoutId>();
_addIfNonNull(children, materialBody, _ScaffoldSlot.body);
_addIfNonNull(children, _modifiedToolBar, _ScaffoldSlot.toolBar);
final List<LayoutId> children = new List<LayoutId>();
_addIfNonNull(children, config.body, _ScaffoldSlot.body);
_addIfNonNull(children, _getModifiedToolBar(padding), _ScaffoldSlot.toolBar);
if (_currentBottomSheet != null ||
(_dismissedBottomSheets != null && _dismissedBottomSheets.isNotEmpty)) {
......@@ -412,7 +418,14 @@ class ScaffoldState extends State<Scaffold> {
));
}
return new CustomMultiChildLayout(children: children, delegate: new _ScaffoldLayout());
return new Material(
child: new CustomMultiChildLayout(
children: children,
delegate: new _ScaffoldLayout(
padding: padding
)
)
);
}
}
......
......@@ -16,11 +16,14 @@ enum Orientation {
/// The result of a media query.
class MediaQueryData {
const MediaQueryData({ this.size });
const MediaQueryData({ this.size, this.padding });
/// The size of the media (e.g, the size of the screen).
final Size size;
/// The padding around the edges of the media (e.g., the screen).
final EdgeDims padding;
/// The orientation of the media (e.g., whether the device is in landscape or portrait mode).
Orientation get orientation {
return size.width > size.height ? Orientation.landscape : Orientation.portrait;
......@@ -30,7 +33,8 @@ class MediaQueryData {
if (other.runtimeType != runtimeType)
return false;
MediaQueryData typedOther = other;
return typedOther.size == size;
return typedOther.size == size
&& typedOther.padding == padding;
}
int get hashCode => size.hashCode;
......
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