// 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')); } }