Add enableDrag configuration for showModalBottomSheet (#46685)

This commit is contained in:
Yuwen Yan 2019-12-17 04:14:24 +08:00 committed by Hans Muller
parent c06bf6503a
commit fba96809f4
2 changed files with 122 additions and 1 deletions

View file

@ -265,7 +265,9 @@ class _ModalBottomSheet<T> extends StatefulWidget {
this.shape,
this.clipBehavior,
this.isScrollControlled = false,
this.enableDrag = true,
}) : assert(isScrollControlled != null),
assert(enableDrag != null),
super(key: key);
final _ModalBottomSheetRoute<T> route;
@ -274,6 +276,7 @@ class _ModalBottomSheet<T> extends StatefulWidget {
final double elevation;
final ShapeBorder shape;
final Clip clipBehavior;
final bool enableDrag;
@override
_ModalBottomSheetState<T> createState() => _ModalBottomSheetState<T>();
@ -326,6 +329,7 @@ class _ModalBottomSheetState<T> extends State<_ModalBottomSheet<T>> {
elevation: widget.elevation,
shape: widget.shape,
clipBehavior: widget.clipBehavior,
enableDrag: widget.enableDrag,
),
),
),
@ -346,10 +350,12 @@ class _ModalBottomSheetRoute<T> extends PopupRoute<T> {
this.clipBehavior,
this.modalBarrierColor,
this.isDismissible = true,
this.enableDrag = true,
@required this.isScrollControlled,
RouteSettings settings,
}) : assert(isScrollControlled != null),
assert(isDismissible != null),
assert(enableDrag != null),
super(settings: settings);
final WidgetBuilder builder;
@ -361,6 +367,7 @@ class _ModalBottomSheetRoute<T> extends PopupRoute<T> {
final Clip clipBehavior;
final Color modalBarrierColor;
final bool isDismissible;
final bool enableDrag;
@override
Duration get transitionDuration => _bottomSheetDuration;
@ -399,6 +406,7 @@ class _ModalBottomSheetRoute<T> extends PopupRoute<T> {
shape: shape,
clipBehavior: clipBehavior,
isScrollControlled: isScrollControlled,
enableDrag: enableDrag,
),
);
if (theme != null)
@ -437,6 +445,9 @@ class _ModalBottomSheetRoute<T> extends PopupRoute<T> {
/// The [isDismissible] parameter specifies whether the bottom sheet will be
/// dismissed when user taps on the scrim.
///
/// The [enableDrag] parameter specifies whether the bottom sheet can be
/// dragged up and down and dismissed by swiping downards.
///
/// The optional [backgroundColor], [elevation], [shape], and [clipBehavior]
/// parameters can be passed in to customize the appearance and behavior of
/// modal bottom sheets.
@ -507,12 +518,14 @@ Future<T> showModalBottomSheet<T>({
bool isScrollControlled = false,
bool useRootNavigator = false,
bool isDismissible = true,
bool enableDrag = true,
}) {
assert(context != null);
assert(builder != null);
assert(isScrollControlled != null);
assert(useRootNavigator != null);
assert(isDismissible != null);
assert(enableDrag != null);
assert(debugCheckHasMediaQuery(context));
assert(debugCheckHasMaterialLocalizations(context));
@ -526,7 +539,8 @@ Future<T> showModalBottomSheet<T>({
shape: shape,
clipBehavior: clipBehavior,
isDismissible: isDismissible,
modalBarrierColor: barrierColor
modalBarrierColor: barrierColor,
enableDrag: enableDrag,
));
}

View file

@ -152,6 +152,113 @@ void main() {
expect(find.text('BottomSheet'), findsOneWidget);
});
testWidgets('Swiping down a modal BottomSheet should dismiss it by default', (WidgetTester tester) async {
BuildContext savedContext;
await tester.pumpWidget(MaterialApp(
home: Builder(
builder: (BuildContext context) {
savedContext = context;
return Container();
},
),
));
await tester.pump();
expect(find.text('BottomSheet'), findsNothing);
bool showBottomSheetThenCalled = false;
showModalBottomSheet<void>(
context: savedContext,
isDismissible: false,
builder: (BuildContext context) => const Text('BottomSheet'),
).then<void>((void value) {
showBottomSheetThenCalled = true;
});
await tester.pumpAndSettle();
expect(find.text('BottomSheet'), findsOneWidget);
expect(showBottomSheetThenCalled, isFalse);
// Swipe the bottom sheet to dismiss it.
await tester.drag(find.text('BottomSheet'), const Offset(0.0, 150.0));
await tester.pumpAndSettle(); // Bottom sheet dismiss animation.
expect(showBottomSheetThenCalled, isTrue);
expect(find.text('BottomSheet'), findsNothing);
});
testWidgets('Swiping down a modal BottomSheet should not dismiss it when enableDrag is false', (WidgetTester tester) async {
BuildContext savedContext;
await tester.pumpWidget(MaterialApp(
home: Builder(
builder: (BuildContext context) {
savedContext = context;
return Container();
},
),
));
await tester.pump();
expect(find.text('BottomSheet'), findsNothing);
bool showBottomSheetThenCalled = false;
showModalBottomSheet<void>(
context: savedContext,
isDismissible: false,
enableDrag: false,
builder: (BuildContext context) => const Text('BottomSheet'),
).then<void>((void value) {
showBottomSheetThenCalled = true;
});
await tester.pumpAndSettle();
expect(find.text('BottomSheet'), findsOneWidget);
expect(showBottomSheetThenCalled, isFalse);
// Swipe the bottom sheet, attempting to dismiss it.
await tester.drag(find.text('BottomSheet'), const Offset(0.0, 150.0));
await tester.pumpAndSettle(); // Bottom sheet should not dismiss.
expect(showBottomSheetThenCalled, isFalse);
expect(find.text('BottomSheet'), findsOneWidget);
});
testWidgets('Swiping down a modal BottomSheet should dismiss it when enableDrag is true', (WidgetTester tester) async {
BuildContext savedContext;
await tester.pumpWidget(MaterialApp(
home: Builder(
builder: (BuildContext context) {
savedContext = context;
return Container();
},
),
));
await tester.pump();
expect(find.text('BottomSheet'), findsNothing);
bool showBottomSheetThenCalled = false;
showModalBottomSheet<void>(
context: savedContext,
isDismissible: false,
enableDrag: true,
builder: (BuildContext context) => const Text('BottomSheet'),
).then<void>((void value) {
showBottomSheetThenCalled = true;
});
await tester.pumpAndSettle();
expect(find.text('BottomSheet'), findsOneWidget);
expect(showBottomSheetThenCalled, isFalse);
// Swipe the bottom sheet to dismiss it.
await tester.drag(find.text('BottomSheet'), const Offset(0.0, 150.0));
await tester.pumpAndSettle(); // Bottom sheet dismiss animation.
expect(showBottomSheetThenCalled, isTrue);
expect(find.text('BottomSheet'), findsNothing);
});
testWidgets('Verify that a downwards fling dismisses a persistent BottomSheet', (WidgetTester tester) async {
final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>();
bool showBottomSheetThenCalled = false;