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