Commit fba96809 authored by Yuwen Yan's avatar Yuwen Yan Committed by Hans Muller

Add enableDrag configuration for showModalBottomSheet (#46685)

parent c06bf650
...@@ -265,7 +265,9 @@ class _ModalBottomSheet<T> extends StatefulWidget { ...@@ -265,7 +265,9 @@ class _ModalBottomSheet<T> extends StatefulWidget {
this.shape, this.shape,
this.clipBehavior, this.clipBehavior,
this.isScrollControlled = false, this.isScrollControlled = false,
this.enableDrag = true,
}) : assert(isScrollControlled != null), }) : assert(isScrollControlled != null),
assert(enableDrag != null),
super(key: key); super(key: key);
final _ModalBottomSheetRoute<T> route; final _ModalBottomSheetRoute<T> route;
...@@ -274,6 +276,7 @@ class _ModalBottomSheet<T> extends StatefulWidget { ...@@ -274,6 +276,7 @@ class _ModalBottomSheet<T> extends StatefulWidget {
final double elevation; final double elevation;
final ShapeBorder shape; final ShapeBorder shape;
final Clip clipBehavior; final Clip clipBehavior;
final bool enableDrag;
@override @override
_ModalBottomSheetState<T> createState() => _ModalBottomSheetState<T>(); _ModalBottomSheetState<T> createState() => _ModalBottomSheetState<T>();
...@@ -326,6 +329,7 @@ class _ModalBottomSheetState<T> extends State<_ModalBottomSheet<T>> { ...@@ -326,6 +329,7 @@ class _ModalBottomSheetState<T> extends State<_ModalBottomSheet<T>> {
elevation: widget.elevation, elevation: widget.elevation,
shape: widget.shape, shape: widget.shape,
clipBehavior: widget.clipBehavior, clipBehavior: widget.clipBehavior,
enableDrag: widget.enableDrag,
), ),
), ),
), ),
...@@ -346,10 +350,12 @@ class _ModalBottomSheetRoute<T> extends PopupRoute<T> { ...@@ -346,10 +350,12 @@ class _ModalBottomSheetRoute<T> extends PopupRoute<T> {
this.clipBehavior, this.clipBehavior,
this.modalBarrierColor, this.modalBarrierColor,
this.isDismissible = true, this.isDismissible = true,
this.enableDrag = true,
@required this.isScrollControlled, @required this.isScrollControlled,
RouteSettings settings, RouteSettings settings,
}) : assert(isScrollControlled != null), }) : assert(isScrollControlled != null),
assert(isDismissible != null), assert(isDismissible != null),
assert(enableDrag != null),
super(settings: settings); super(settings: settings);
final WidgetBuilder builder; final WidgetBuilder builder;
...@@ -361,6 +367,7 @@ class _ModalBottomSheetRoute<T> extends PopupRoute<T> { ...@@ -361,6 +367,7 @@ class _ModalBottomSheetRoute<T> extends PopupRoute<T> {
final Clip clipBehavior; final Clip clipBehavior;
final Color modalBarrierColor; final Color modalBarrierColor;
final bool isDismissible; final bool isDismissible;
final bool enableDrag;
@override @override
Duration get transitionDuration => _bottomSheetDuration; Duration get transitionDuration => _bottomSheetDuration;
...@@ -399,6 +406,7 @@ class _ModalBottomSheetRoute<T> extends PopupRoute<T> { ...@@ -399,6 +406,7 @@ class _ModalBottomSheetRoute<T> extends PopupRoute<T> {
shape: shape, shape: shape,
clipBehavior: clipBehavior, clipBehavior: clipBehavior,
isScrollControlled: isScrollControlled, isScrollControlled: isScrollControlled,
enableDrag: enableDrag,
), ),
); );
if (theme != null) if (theme != null)
...@@ -437,6 +445,9 @@ class _ModalBottomSheetRoute<T> extends PopupRoute<T> { ...@@ -437,6 +445,9 @@ class _ModalBottomSheetRoute<T> extends PopupRoute<T> {
/// The [isDismissible] parameter specifies whether the bottom sheet will be /// The [isDismissible] parameter specifies whether the bottom sheet will be
/// dismissed when user taps on the scrim. /// 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] /// The optional [backgroundColor], [elevation], [shape], and [clipBehavior]
/// parameters can be passed in to customize the appearance and behavior of /// parameters can be passed in to customize the appearance and behavior of
/// modal bottom sheets. /// modal bottom sheets.
...@@ -507,12 +518,14 @@ Future<T> showModalBottomSheet<T>({ ...@@ -507,12 +518,14 @@ Future<T> showModalBottomSheet<T>({
bool isScrollControlled = false, bool isScrollControlled = false,
bool useRootNavigator = false, bool useRootNavigator = false,
bool isDismissible = true, bool isDismissible = true,
bool enableDrag = true,
}) { }) {
assert(context != null); assert(context != null);
assert(builder != null); assert(builder != null);
assert(isScrollControlled != null); assert(isScrollControlled != null);
assert(useRootNavigator != null); assert(useRootNavigator != null);
assert(isDismissible != null); assert(isDismissible != null);
assert(enableDrag != null);
assert(debugCheckHasMediaQuery(context)); assert(debugCheckHasMediaQuery(context));
assert(debugCheckHasMaterialLocalizations(context)); assert(debugCheckHasMaterialLocalizations(context));
...@@ -526,7 +539,8 @@ Future<T> showModalBottomSheet<T>({ ...@@ -526,7 +539,8 @@ Future<T> showModalBottomSheet<T>({
shape: shape, shape: shape,
clipBehavior: clipBehavior, clipBehavior: clipBehavior,
isDismissible: isDismissible, isDismissible: isDismissible,
modalBarrierColor: barrierColor modalBarrierColor: barrierColor,
enableDrag: enableDrag,
)); ));
} }
......
...@@ -152,6 +152,113 @@ void main() { ...@@ -152,6 +152,113 @@ void main() {
expect(find.text('BottomSheet'), findsOneWidget); 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 { testWidgets('Verify that a downwards fling dismisses a persistent BottomSheet', (WidgetTester tester) async {
final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>(); final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>();
bool showBottomSheetThenCalled = false; bool showBottomSheetThenCalled = false;
......
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