parent
076594b3fd
commit
da27d674a4
@ -3,6 +3,7 @@
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
@ -38,6 +39,8 @@ class Dialog extends StatelessWidget {
|
||||
const Dialog({
|
||||
Key key,
|
||||
this.child,
|
||||
this.insetAnimationDuration: const Duration(milliseconds: 100),
|
||||
this.insetAnimationCurve: Curves.decelerate,
|
||||
}) : super(key: key);
|
||||
|
||||
/// The widget below this widget in the tree.
|
||||
@ -45,25 +48,46 @@ class Dialog extends StatelessWidget {
|
||||
/// {@macro flutter.widgets.child}
|
||||
final Widget child;
|
||||
|
||||
/// The duration of the animation to show when the system keyboard intrudes
|
||||
/// into the space that the dialog is placed in.
|
||||
///
|
||||
/// Defaults to 100 milliseconds.
|
||||
final Duration insetAnimationDuration;
|
||||
|
||||
/// The curve to use for the animation shown when the system keyboard intrudes
|
||||
/// into the space that the dialog is placed in.
|
||||
///
|
||||
/// Defaults to [Curves.fastOutSlowIn].
|
||||
final Curve insetAnimationCurve;
|
||||
|
||||
Color _getColor(BuildContext context) {
|
||||
return Theme.of(context).dialogBackgroundColor;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return new Center(
|
||||
child: new Container(
|
||||
margin: const EdgeInsets.symmetric(horizontal: 40.0, vertical: 24.0),
|
||||
child: new ConstrainedBox(
|
||||
constraints: const BoxConstraints(minWidth: 280.0),
|
||||
child: new Material(
|
||||
elevation: 24.0,
|
||||
color: _getColor(context),
|
||||
type: MaterialType.card,
|
||||
child: child
|
||||
)
|
||||
)
|
||||
)
|
||||
return new AnimatedPadding(
|
||||
padding: MediaQuery.of(context).viewInsets + const EdgeInsets.symmetric(horizontal: 40.0, vertical: 24.0),
|
||||
duration: insetAnimationDuration,
|
||||
curve: insetAnimationCurve,
|
||||
child: new MediaQuery.removeViewInsets(
|
||||
removeLeft: true,
|
||||
removeTop: true,
|
||||
removeRight: true,
|
||||
removeBottom: true,
|
||||
context: context,
|
||||
child: new Center(
|
||||
child: new ConstrainedBox(
|
||||
constraints: const BoxConstraints(minWidth: 280.0),
|
||||
child: new Material(
|
||||
elevation: 24.0,
|
||||
color: _getColor(context),
|
||||
type: MaterialType.card,
|
||||
child: child,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -140,7 +140,7 @@ class MediaQueryData {
|
||||
);
|
||||
}
|
||||
|
||||
/// Creates a copy of this media query data but with the given paddings
|
||||
/// Creates a copy of this media query data but with the given [padding]s
|
||||
/// replaced with zero.
|
||||
///
|
||||
/// The `removeLeft`, `removeTop`, `removeRight`, and `removeBottom` arguments
|
||||
@ -153,6 +153,7 @@ class MediaQueryData {
|
||||
/// from the ambient [MediaQuery].
|
||||
/// * [SafeArea], which both removes the padding from the [MediaQuery] and
|
||||
/// adds a [Padding] widget.
|
||||
/// * [removeViewInsets], the same thing but for [viewInsets].
|
||||
MediaQueryData removePadding({
|
||||
bool removeLeft: false,
|
||||
bool removeTop: false,
|
||||
@ -176,6 +177,41 @@ class MediaQueryData {
|
||||
);
|
||||
}
|
||||
|
||||
/// Creates a copy of this media query data but with the given [viewInsets]
|
||||
/// replaced with zero.
|
||||
///
|
||||
/// The `removeLeft`, `removeTop`, `removeRight`, and `removeBottom` arguments
|
||||
/// must not be null. If all four are false (the default) then this
|
||||
/// [MediaQueryData] is returned unmodified.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [new MediaQuery.removeViewInsets], which uses this method to remove
|
||||
/// padding from the ambient [MediaQuery].
|
||||
/// * [removePadding], the same thing but for [padding].
|
||||
MediaQueryData removeViewInsets({
|
||||
bool removeLeft: false,
|
||||
bool removeTop: false,
|
||||
bool removeRight: false,
|
||||
bool removeBottom: false,
|
||||
}) {
|
||||
if (!(removeLeft || removeTop || removeRight || removeBottom))
|
||||
return this;
|
||||
return new MediaQueryData(
|
||||
size: size,
|
||||
devicePixelRatio: devicePixelRatio,
|
||||
textScaleFactor: textScaleFactor,
|
||||
padding: padding,
|
||||
viewInsets: viewInsets.copyWith(
|
||||
left: removeLeft ? 0.0 : null,
|
||||
top: removeTop ? 0.0 : null,
|
||||
right: removeRight ? 0.0 : null,
|
||||
bottom: removeBottom ? 0.0 : null,
|
||||
),
|
||||
alwaysUse24HourFormat: alwaysUse24HourFormat,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
if (other.runtimeType != runtimeType)
|
||||
@ -194,9 +230,14 @@ class MediaQueryData {
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return '$runtimeType(size: $size, devicePixelRatio: $devicePixelRatio, '
|
||||
'textScaleFactor: $textScaleFactor, padding: $padding, '
|
||||
'viewInsets: $viewInsets, alwaysUse24HourFormat: $alwaysUse24HourFormat)';
|
||||
return '$runtimeType('
|
||||
'size: $size, '
|
||||
'devicePixelRatio: $devicePixelRatio, '
|
||||
'textScaleFactor: $textScaleFactor, '
|
||||
'padding: $padding, '
|
||||
'viewInsets: $viewInsets, '
|
||||
'alwaysUse24HourFormat: $alwaysUse24HourFormat'
|
||||
')';
|
||||
}
|
||||
}
|
||||
|
||||
@ -236,8 +277,8 @@ class MediaQuery extends InheritedWidget {
|
||||
/// the given context, but removes the specified paddings.
|
||||
///
|
||||
/// This should be inserted into the widget tree when the [MediaQuery] padding
|
||||
/// is consumed in such a way that the padding is no longer exposed to its
|
||||
/// descendents or siblings.
|
||||
/// is consumed by a widget in such a way that the padding is no longer
|
||||
/// exposed to the widget's descendents or siblings.
|
||||
///
|
||||
/// The [context] argument is required, must not be null, and must have a
|
||||
/// [MediaQuery] in scope.
|
||||
@ -253,6 +294,8 @@ class MediaQuery extends InheritedWidget {
|
||||
///
|
||||
/// * [SafeArea], which both removes the padding from the [MediaQuery] and
|
||||
/// adds a [Padding] widget.
|
||||
/// * [MediaQueryData.padding], the affected property of the [MediaQueryData].
|
||||
/// * [new removeViewInsets], the same thing but for removing view insets.
|
||||
factory MediaQuery.removePadding({
|
||||
Key key,
|
||||
@required BuildContext context,
|
||||
@ -274,6 +317,48 @@ class MediaQuery extends InheritedWidget {
|
||||
);
|
||||
}
|
||||
|
||||
/// Creates a new [MediaQuery] that inherits from the ambient [MediaQuery] from
|
||||
/// the given context, but removes the specified view insets.
|
||||
///
|
||||
/// This should be inserted into the widget tree when the [MediaQuery] view
|
||||
/// insets are consumed by a widget in such a way that the view insets are no
|
||||
/// longer exposed to the widget's descendents or siblings.
|
||||
///
|
||||
/// The [context] argument is required, must not be null, and must have a
|
||||
/// [MediaQuery] in scope.
|
||||
///
|
||||
/// The `removeLeft`, `removeTop`, `removeRight`, and `removeBottom` arguments
|
||||
/// must not be null. If all four are false (the default) then the returned
|
||||
/// [MediaQuery] reuses the ambient [MediaQueryData] unmodified, which is not
|
||||
/// particularly useful.
|
||||
///
|
||||
/// The [child] argument is required and must not be null.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [MediaQueryData.viewInsets], the affected property of the [MediaQueryData].
|
||||
/// * [new removePadding], the same thing but for removing paddings.
|
||||
factory MediaQuery.removeViewInsets({
|
||||
Key key,
|
||||
@required BuildContext context,
|
||||
bool removeLeft: false,
|
||||
bool removeTop: false,
|
||||
bool removeRight: false,
|
||||
bool removeBottom: false,
|
||||
@required Widget child,
|
||||
}) {
|
||||
return new MediaQuery(
|
||||
key: key,
|
||||
data: MediaQuery.of(context).removeViewInsets(
|
||||
removeLeft: removeLeft,
|
||||
removeTop: removeTop,
|
||||
removeRight: removeRight,
|
||||
removeBottom: removeBottom,
|
||||
),
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
|
||||
/// Contains information about the current media.
|
||||
///
|
||||
/// For example, the [MediaQueryData.size] property contains the width and
|
||||
|
@ -242,8 +242,9 @@ void main() {
|
||||
semantics.dispose();
|
||||
});
|
||||
|
||||
testWidgets('Dialogs removes MediaQuery padding', (WidgetTester tester) async {
|
||||
testWidgets('Dialogs removes MediaQuery padding and view insets', (WidgetTester tester) async {
|
||||
BuildContext outerContext;
|
||||
BuildContext routeContext;
|
||||
BuildContext dialogContext;
|
||||
|
||||
await tester.pumpWidget(new Localizations(
|
||||
@ -255,6 +256,7 @@ void main() {
|
||||
child: new MediaQuery(
|
||||
data: const MediaQueryData(
|
||||
padding: const EdgeInsets.all(50.0),
|
||||
viewInsets: const EdgeInsets.only(left: 25.0, bottom: 75.0),
|
||||
),
|
||||
child: new Navigator(
|
||||
onGenerateRoute: (_) {
|
||||
@ -273,14 +275,61 @@ void main() {
|
||||
context: outerContext,
|
||||
barrierDismissible: false,
|
||||
builder: (BuildContext context) {
|
||||
dialogContext = context;
|
||||
return new Container();
|
||||
routeContext = context;
|
||||
return new Dialog(
|
||||
child: new Builder(
|
||||
builder: (BuildContext context) {
|
||||
dialogContext = context;
|
||||
return const Placeholder();
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
await tester.pump();
|
||||
|
||||
expect(MediaQuery.of(outerContext).padding, const EdgeInsets.all(50.0));
|
||||
expect(MediaQuery.of(routeContext).padding, EdgeInsets.zero);
|
||||
expect(MediaQuery.of(dialogContext).padding, EdgeInsets.zero);
|
||||
expect(MediaQuery.of(outerContext).viewInsets, const EdgeInsets.only(left: 25.0, bottom: 75.0));
|
||||
expect(MediaQuery.of(routeContext).viewInsets, const EdgeInsets.only(left: 25.0, bottom: 75.0));
|
||||
expect(MediaQuery.of(dialogContext).viewInsets, EdgeInsets.zero);
|
||||
});
|
||||
|
||||
testWidgets('Dialog widget insets by viewInsets', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
const MediaQuery(
|
||||
data: const MediaQueryData(
|
||||
viewInsets: const EdgeInsets.fromLTRB(10.0, 20.0, 30.0, 40.0),
|
||||
),
|
||||
child: const Dialog(
|
||||
child: const Placeholder(),
|
||||
),
|
||||
),
|
||||
);
|
||||
expect(
|
||||
tester.getRect(find.byType(Placeholder)),
|
||||
new Rect.fromLTRB(10.0 + 40.0, 20.0 + 24.0, 800.0 - (40.0 + 30.0), 600.0 - (24.0 + 40.0)),
|
||||
);
|
||||
await tester.pumpWidget(
|
||||
const MediaQuery(
|
||||
data: const MediaQueryData(
|
||||
viewInsets: const EdgeInsets.fromLTRB(0.0, 0.0, 0.0, 0.0),
|
||||
),
|
||||
child: const Dialog(
|
||||
child: const Placeholder(),
|
||||
),
|
||||
),
|
||||
);
|
||||
expect( // no change because this is an animation
|
||||
tester.getRect(find.byType(Placeholder)),
|
||||
new Rect.fromLTRB(10.0 + 40.0, 20.0 + 24.0, 800.0 - (40.0 + 30.0), 600.0 - (24.0 + 40.0)),
|
||||
);
|
||||
await tester.pump(const Duration(seconds: 1));
|
||||
expect( // animation finished
|
||||
tester.getRect(find.byType(Placeholder)),
|
||||
new Rect.fromLTRB(40.0, 24.0, 800.0 - 40.0, 600.0 - 24.0),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
@ -96,9 +96,9 @@ void main() {
|
||||
builder: (BuildContext context) {
|
||||
return new MediaQuery.removePadding(
|
||||
context: context,
|
||||
removeLeft: true,
|
||||
removeTop: true,
|
||||
removeRight: true,
|
||||
removeLeft: true,
|
||||
removeBottom: true,
|
||||
child: new Builder(
|
||||
builder: (BuildContext context) {
|
||||
@ -107,7 +107,8 @@ void main() {
|
||||
}
|
||||
),
|
||||
);
|
||||
}),
|
||||
},
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
@ -118,4 +119,50 @@ void main() {
|
||||
expect(unpadded.viewInsets, viewInsets);
|
||||
expect(unpadded.alwaysUse24HourFormat, true);
|
||||
});
|
||||
|
||||
testWidgets('MediaQuery.removeViewInsets removes specified viewInsets', (WidgetTester tester) async {
|
||||
const Size size = const Size(2.0, 4.0);
|
||||
const double devicePixelRatio = 2.0;
|
||||
const double textScaleFactor = 1.2;
|
||||
const EdgeInsets padding = const EdgeInsets.only(top: 5.0, right: 6.0, left: 7.0, bottom: 8.0);
|
||||
const EdgeInsets viewInsets = const EdgeInsets.only(top: 1.0, right: 2.0, left: 3.0, bottom: 4.0);
|
||||
|
||||
MediaQueryData unpadded;
|
||||
await tester.pumpWidget(
|
||||
new MediaQuery(
|
||||
data: const MediaQueryData(
|
||||
size: size,
|
||||
devicePixelRatio: devicePixelRatio,
|
||||
textScaleFactor: textScaleFactor,
|
||||
padding: padding,
|
||||
viewInsets: viewInsets,
|
||||
alwaysUse24HourFormat: true,
|
||||
),
|
||||
child: new Builder(
|
||||
builder: (BuildContext context) {
|
||||
return new MediaQuery.removeViewInsets(
|
||||
context: context,
|
||||
removeLeft: true,
|
||||
removeTop: true,
|
||||
removeRight: true,
|
||||
removeBottom: true,
|
||||
child: new Builder(
|
||||
builder: (BuildContext context) {
|
||||
unpadded = MediaQuery.of(context);
|
||||
return new Container();
|
||||
}
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
expect(unpadded.size, size);
|
||||
expect(unpadded.devicePixelRatio, devicePixelRatio);
|
||||
expect(unpadded.textScaleFactor, textScaleFactor);
|
||||
expect(unpadded.padding, padding);
|
||||
expect(unpadded.viewInsets, EdgeInsets.zero);
|
||||
expect(unpadded.alwaysUse24HourFormat, true);
|
||||
});
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user