Unverified Commit 4b878dc6 authored by Chris Bracken's avatar Chris Bracken Committed by GitHub

Add minimum insets to SafeArea (#14505)

As a convenience, this adds a set of minimum padding to apply. The
greater of the minimum padding and the media padding is applied to each
edge.
parent 35c2267f
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'dart:math' as math;
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'basic.dart'; import 'basic.dart';
...@@ -9,8 +11,8 @@ import 'debug.dart'; ...@@ -9,8 +11,8 @@ import 'debug.dart';
import 'framework.dart'; import 'framework.dart';
import 'media_query.dart'; import 'media_query.dart';
/// A widget that insets its child by sufficient padding to avoid /// A widget that insets its child by sufficient padding to avoid intrusions by
/// intrusions by the operating system. /// the operating system.
/// ///
/// For example, this will indent the child by enough to avoid the status bar at /// For example, this will indent the child by enough to avoid the status bar at
/// the top of the screen. /// the top of the screen.
...@@ -18,6 +20,9 @@ import 'media_query.dart'; ...@@ -18,6 +20,9 @@ import 'media_query.dart';
/// It will also indent the child by the amount necessary to avoid The Notch on /// 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. /// 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: /// See also:
/// ///
/// * [SliverSafeArea], for insetting slivers to avoid operating system /// * [SliverSafeArea], for insetting slivers to avoid operating system
...@@ -29,13 +34,15 @@ import 'media_query.dart'; ...@@ -29,13 +34,15 @@ import 'media_query.dart';
class SafeArea extends StatelessWidget { class SafeArea extends StatelessWidget {
/// Creates a widget that avoids operating system interfaces. /// Creates a widget that avoids operating system interfaces.
/// ///
/// The [left], [top], [right], and [bottom] arguments must not be null. /// The [left], [top], [right], [bottom], and [minimum] arguments must not be
/// null.
const SafeArea({ const SafeArea({
Key key, Key key,
this.left: true, this.left: true,
this.top: true, this.top: true,
this.right: true, this.right: true,
this.bottom: true, this.bottom: true,
this.minimum: EdgeInsets.zero,
@required this.child, @required this.child,
}) : assert(left != null), }) : assert(left != null),
assert(top != null), assert(top != null),
...@@ -56,6 +63,11 @@ class SafeArea extends StatelessWidget { ...@@ -56,6 +63,11 @@ class SafeArea extends StatelessWidget {
/// Whether to avoid system intrusions on the bottom side of the screen. /// Whether to avoid system intrusions on the bottom side of the screen.
final bool bottom; 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 widget below this widget in the tree.
/// ///
/// The padding on the [MediaQuery] for the [child] will be suitably adjusted /// The padding on the [MediaQuery] for the [child] will be suitably adjusted
...@@ -70,10 +82,10 @@ class SafeArea extends StatelessWidget { ...@@ -70,10 +82,10 @@ class SafeArea extends StatelessWidget {
final EdgeInsets padding = MediaQuery.of(context).padding; final EdgeInsets padding = MediaQuery.of(context).padding;
return new Padding( return new Padding(
padding: new EdgeInsets.only( padding: new EdgeInsets.only(
left: left ? padding.left : 0.0, left: math.max(left ? padding.left : 0.0, minimum.left),
top: top ? padding.top : 0.0, top: math.max(top ? padding.top : 0.0, minimum.top),
right: right ? padding.right : 0.0, right: math.max(right ? padding.right : 0.0, minimum.right),
bottom: bottom ? padding.bottom : 0.0, bottom: math.max(bottom ? padding.bottom : 0.0, minimum.bottom),
), ),
child: new MediaQuery.removePadding( child: new MediaQuery.removePadding(
context: context, context: context,
...@@ -106,6 +118,9 @@ class SafeArea extends StatelessWidget { ...@@ -106,6 +118,9 @@ class SafeArea extends StatelessWidget {
/// on the iPhone X, or other similar creative physical features of the /// on the iPhone X, or other similar creative physical features of the
/// display. /// display.
/// ///
/// When a [minimum] padding is specified, the greater of the minimum padding
/// or the safe area padding will be applied.
///
/// See also: /// See also:
/// ///
/// * [SafeArea], for insetting widgets to avoid operating system intrusions. /// * [SafeArea], for insetting widgets to avoid operating system intrusions.
...@@ -116,13 +131,14 @@ class SafeArea extends StatelessWidget { ...@@ -116,13 +131,14 @@ class SafeArea extends StatelessWidget {
class SliverSafeArea extends StatelessWidget { class SliverSafeArea extends StatelessWidget {
/// Creates a sliver that avoids operating system interfaces. /// Creates a sliver that avoids operating system interfaces.
/// ///
/// The [left], [top], [right], and [bottom] arguments must not be null. /// The [left], [top], [right], [bottom], and [minimum] arguments must not be null.
const SliverSafeArea({ const SliverSafeArea({
Key key, Key key,
this.left: true, this.left: true,
this.top: true, this.top: true,
this.right: true, this.right: true,
this.bottom: true, this.bottom: true,
this.minimum: EdgeInsets.zero,
@required this.sliver, @required this.sliver,
}) : assert(left != null), }) : assert(left != null),
assert(top != null), assert(top != null),
...@@ -143,6 +159,11 @@ class SliverSafeArea extends StatelessWidget { ...@@ -143,6 +159,11 @@ class SliverSafeArea extends StatelessWidget {
/// Whether to avoid system intrusions on the bottom side of the screen. /// Whether to avoid system intrusions on the bottom side of the screen.
final bool bottom; 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 sliver below this sliver in the tree.
/// ///
/// The padding on the [MediaQuery] for the [sliver] will be suitably adjusted /// The padding on the [MediaQuery] for the [sliver] will be suitably adjusted
...@@ -155,10 +176,10 @@ class SliverSafeArea extends StatelessWidget { ...@@ -155,10 +176,10 @@ class SliverSafeArea extends StatelessWidget {
final EdgeInsets padding = MediaQuery.of(context).padding; final EdgeInsets padding = MediaQuery.of(context).padding;
return new SliverPadding( return new SliverPadding(
padding: new EdgeInsets.only( padding: new EdgeInsets.only(
left: left ? padding.left : 0.0, left: math.max(left ? padding.left : 0.0, minimum.left),
top: top ? padding.top : 0.0, top: math.max(top ? padding.top : 0.0, minimum.top),
right: right ? padding.right : 0.0, right: math.max(right ? padding.right : 0.0, minimum.right),
bottom: bottom ? padding.bottom : 0.0, bottom: math.max(bottom ? padding.bottom : 0.0, minimum.bottom),
), ),
sliver: new MediaQuery.removePadding( sliver: new MediaQuery.removePadding(
context: context, context: context,
......
...@@ -22,6 +22,21 @@ void main() { ...@@ -22,6 +22,21 @@ void main() {
expect(tester.getBottomRight(find.byType(Placeholder)), const Offset(780.0, 580.0)); expect(tester.getBottomRight(find.byType(Placeholder)), const Offset(780.0, 580.0));
}); });
testWidgets('SafeArea - with minimums', (WidgetTester tester) async {
await tester.pumpWidget(
const MediaQuery(
data: const MediaQueryData(padding: const EdgeInsets.all(20.0)),
child: const SafeArea(
top: false,
minimum: const EdgeInsets.fromLTRB(0.0, 10.0, 20.0, 30.0),
child: const Placeholder(),
),
),
);
expect(tester.getTopLeft(find.byType(Placeholder)), const Offset(20.0, 10.0));
expect(tester.getBottomRight(find.byType(Placeholder)), const Offset(780.0, 570.0));
});
testWidgets('SafeArea - nested', (WidgetTester tester) async { testWidgets('SafeArea - nested', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(
const MediaQuery( const MediaQuery(
...@@ -119,6 +134,24 @@ void main() { ...@@ -119,6 +134,24 @@ void main() {
]); ]);
}); });
testWidgets('SliverSafeArea - basic', (WidgetTester tester) async {
await tester.pumpWidget(
buildWidget(
const EdgeInsets.all(20.0),
const SliverSafeArea(
top: false,
minimum: const EdgeInsets.fromLTRB(0.0, 10.0, 20.0, 30.0),
sliver: const SliverToBoxAdapter(child: const SizedBox(width: 800.0, height: 100.0, child: const Text('padded'))),
),
),
);
verify(tester, <Rect>[
new Rect.fromLTWH(0.0, 0.0, 800.0, 100.0),
new Rect.fromLTWH(20.0, 110.0, 760.0, 100.0),
new Rect.fromLTWH(0.0, 240.0, 800.0, 100.0),
]);
});
testWidgets('SliverSafeArea - nested', (WidgetTester tester) async { testWidgets('SliverSafeArea - nested', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(
buildWidget( buildWidget(
......
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