blob: f2ad0b480be487f8d5b9938c66adb55de441d1c3 [file] [log] [blame]
// 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:math' as math;
import 'package:flutter/foundation.dart';
import 'basic.dart';
import 'debug.dart';
import 'framework.dart';
import 'media_query.dart';
/// A widget that insets its child by sufficient padding to avoid intrusions by
/// the operating system.
///
/// For example, this will indent the child by enough to avoid the status bar at
/// the top of the screen.
///
/// It will also indent the child by the amount necessary to avoid The Notch on
/// the iPhone X, or other similar creative physical features of the display.
///
/// When a [minimum] padding is specified, the greater of the minimum padding
/// or the safe area padding will be applied.
///
/// See also:
///
/// * [SliverSafeArea], for insetting slivers to avoid operating system
/// intrusions.
/// * [Padding], for insetting widgets in general.
/// * [MediaQuery], from which the window padding is obtained.
/// * [dart:ui.Window.padding], which reports the padding from the operating
/// system.
class SafeArea extends StatelessWidget {
/// Creates a widget that avoids operating system interfaces.
///
/// The [left], [top], [right], [bottom], and [minimum] arguments must not be
/// null.
const SafeArea({
Key key,
this.left: true,
this.top: true,
this.right: true,
this.bottom: true,
this.minimum: EdgeInsets.zero,
@required this.child,
}) : assert(left != null),
assert(top != null),
assert(right != null),
assert(bottom != null),
super(key: key);
/// Whether to avoid system intrusions on the left.
final bool left;
/// Whether to avoid system intrusions at the top of the screen, typically the
/// system status bar.
final bool top;
/// Whether to avoid system intrusions on the right.
final bool right;
/// Whether to avoid system intrusions on the bottom side of the screen.
final bool bottom;
/// This minimum padding to apply.
///
/// The greater of the minimum insets and the media padding will be applied.
final EdgeInsets minimum;
/// The widget below this widget in the tree.
///
/// The padding on the [MediaQuery] for the [child] will be suitably adjusted
/// to zero out any sides that were avoided by this widget.
///
/// {@macro flutter.widgets.child}
final Widget child;
@override
Widget build(BuildContext context) {
assert(debugCheckHasMediaQuery(context));
final EdgeInsets padding = MediaQuery.of(context).padding;
return new Padding(
padding: new EdgeInsets.only(
left: math.max(left ? padding.left : 0.0, minimum.left),
top: math.max(top ? padding.top : 0.0, minimum.top),
right: math.max(right ? padding.right : 0.0, minimum.right),
bottom: math.max(bottom ? padding.bottom : 0.0, minimum.bottom),
),
child: new MediaQuery.removePadding(
context: context,
removeLeft: left,
removeTop: top,
removeRight: right,
removeBottom: bottom,
child: child,
),
);
}
@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties.add(new FlagProperty('left', value: left, ifTrue: 'avoid left padding'));
properties.add(new FlagProperty('top', value: left, ifTrue: 'avoid top padding'));
properties.add(new FlagProperty('right', value: left, ifTrue: 'avoid right padding'));
properties.add(new FlagProperty('bottom', value: left, ifTrue: 'avoid bottom padding'));
}
}
/// A sliver that insets another sliver by sufficient padding to avoid
/// intrusions by the operating system.
///
/// For example, this will indent the sliver by enough to avoid the status bar
/// at the top of the screen.
///
/// It will also indent the sliver by the amount necessary to avoid The Notch
/// on the iPhone X, or other similar creative physical features of the
/// display.
///
/// When a [minimum] padding is specified, the greater of the minimum padding
/// or the safe area padding will be applied.
///
/// See also:
///
/// * [SafeArea], for insetting widgets to avoid operating system intrusions.
/// * [SliverPadding], for insetting slivers in general.
/// * [MediaQuery], from which the window padding is obtained.
/// * [dart:ui.Window.padding], which reports the padding from the operating
/// system.
class SliverSafeArea extends StatelessWidget {
/// Creates a sliver that avoids operating system interfaces.
///
/// The [left], [top], [right], [bottom], and [minimum] arguments must not be null.
const SliverSafeArea({
Key key,
this.left: true,
this.top: true,
this.right: true,
this.bottom: true,
this.minimum: EdgeInsets.zero,
@required this.sliver,
}) : assert(left != null),
assert(top != null),
assert(right != null),
assert(bottom != null),
super(key: key);
/// Whether to avoid system intrusions on the left.
final bool left;
/// Whether to avoid system intrusions at the top of the screen, typically the
/// system status bar.
final bool top;
/// Whether to avoid system intrusions on the right.
final bool right;
/// Whether to avoid system intrusions on the bottom side of the screen.
final bool bottom;
/// This minimum padding to apply.
///
/// The greater of the minimum padding and the media padding is be applied.
final EdgeInsets minimum;
/// The sliver below this sliver in the tree.
///
/// The padding on the [MediaQuery] for the [sliver] will be suitably adjusted
/// to zero out any sides that were avoided by this sliver.
final Widget sliver;
@override
Widget build(BuildContext context) {
assert(debugCheckHasMediaQuery(context));
final EdgeInsets padding = MediaQuery.of(context).padding;
return new SliverPadding(
padding: new EdgeInsets.only(
left: math.max(left ? padding.left : 0.0, minimum.left),
top: math.max(top ? padding.top : 0.0, minimum.top),
right: math.max(right ? padding.right : 0.0, minimum.right),
bottom: math.max(bottom ? padding.bottom : 0.0, minimum.bottom),
),
sliver: new MediaQuery.removePadding(
context: context,
removeLeft: left,
removeTop: top,
removeRight: right,
removeBottom: bottom,
child: sliver,
),
);
}
@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties.add(new FlagProperty('left', value: left, ifTrue: 'avoid left padding'));
properties.add(new FlagProperty('top', value: left, ifTrue: 'avoid top padding'));
properties.add(new FlagProperty('right', value: left, ifTrue: 'avoid right padding'));
properties.add(new FlagProperty('bottom', value: left, ifTrue: 'avoid bottom padding'));
}
}