mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
Tapping a modal bottom sheet should not dismiss it by default (#32528)
Removed the GestureDetector from the modal bottom sheet that dismissed it on tap and updated several tests to accommodate this change.
This commit is contained in:
parent
20299a2c17
commit
3d93f24c05
@ -24,7 +24,7 @@ class ModalBottomSheetDemo extends StatelessWidget {
|
|||||||
return Container(
|
return Container(
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(32.0),
|
padding: const EdgeInsets.all(32.0),
|
||||||
child: Text('This is the modal bottom sheet. Tap anywhere to dismiss.',
|
child: Text('This is the modal bottom sheet. Slide down to dismiss.',
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Theme.of(context).accentColor,
|
color: Theme.of(context).accentColor,
|
||||||
|
@ -281,43 +281,36 @@ class _ModalBottomSheetState<T> extends State<_ModalBottomSheet<T>> {
|
|||||||
final MaterialLocalizations localizations = MaterialLocalizations.of(context);
|
final MaterialLocalizations localizations = MaterialLocalizations.of(context);
|
||||||
final String routeLabel = _getRouteLabel(localizations);
|
final String routeLabel = _getRouteLabel(localizations);
|
||||||
|
|
||||||
return GestureDetector(
|
return AnimatedBuilder(
|
||||||
excludeFromSemantics: true,
|
animation: widget.route.animation,
|
||||||
onTap: () {
|
builder: (BuildContext context, Widget child) {
|
||||||
if (widget.route.isCurrent)
|
// Disable the initial animation when accessible navigation is on so
|
||||||
Navigator.pop(context);
|
// that the semantics are added to the tree at the correct time.
|
||||||
},
|
final double animationValue = mediaQuery.accessibleNavigation ? 1.0 : widget.route.animation.value;
|
||||||
child: AnimatedBuilder(
|
return Semantics(
|
||||||
animation: widget.route.animation,
|
scopesRoute: true,
|
||||||
builder: (BuildContext context, Widget child) {
|
namesRoute: true,
|
||||||
// Disable the initial animation when accessible navigation is on so
|
label: routeLabel,
|
||||||
// that the semantics are added to the tree at the correct time.
|
explicitChildNodes: true,
|
||||||
final double animationValue = mediaQuery.accessibleNavigation ? 1.0 : widget.route.animation.value;
|
child: ClipRect(
|
||||||
return Semantics(
|
child: CustomSingleChildLayout(
|
||||||
scopesRoute: true,
|
delegate: _ModalBottomSheetLayout(animationValue, widget.isScrollControlled),
|
||||||
namesRoute: true,
|
child: BottomSheet(
|
||||||
label: routeLabel,
|
animationController: widget.route._animationController,
|
||||||
explicitChildNodes: true,
|
onClosing: () {
|
||||||
child: ClipRect(
|
if (widget.route.isCurrent) {
|
||||||
child: CustomSingleChildLayout(
|
Navigator.pop(context);
|
||||||
delegate: _ModalBottomSheetLayout(animationValue, widget.isScrollControlled),
|
}
|
||||||
child: BottomSheet(
|
},
|
||||||
animationController: widget.route._animationController,
|
builder: widget.route.builder,
|
||||||
onClosing: () {
|
backgroundColor: widget.backgroundColor,
|
||||||
if (widget.route.isCurrent) {
|
elevation: widget.elevation,
|
||||||
Navigator.pop(context);
|
shape: widget.shape,
|
||||||
}
|
|
||||||
},
|
|
||||||
builder: widget.route.builder,
|
|
||||||
backgroundColor: widget.backgroundColor,
|
|
||||||
elevation: widget.elevation,
|
|
||||||
shape: widget.shape,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
),
|
||||||
},
|
);
|
||||||
),
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ import 'package:flutter/gestures.dart';
|
|||||||
import '../widgets/semantics_tester.dart';
|
import '../widgets/semantics_tester.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
testWidgets('Verify that a tap dismisses a modal BottomSheet', (WidgetTester tester) async {
|
testWidgets('Tapping on a modal BottomSheet should not dismiss it', (WidgetTester tester) async {
|
||||||
BuildContext savedContext;
|
BuildContext savedContext;
|
||||||
|
|
||||||
await tester.pumpWidget(MaterialApp(
|
await tester.pumpWidget(MaterialApp(
|
||||||
@ -33,28 +33,41 @@ void main() {
|
|||||||
showBottomSheetThenCalled = true;
|
showBottomSheetThenCalled = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
await tester.pump(); // bottom sheet show animation starts
|
await tester.pumpAndSettle();
|
||||||
await tester.pump(const Duration(seconds: 1)); // animation done
|
|
||||||
expect(find.text('BottomSheet'), findsOneWidget);
|
expect(find.text('BottomSheet'), findsOneWidget);
|
||||||
expect(showBottomSheetThenCalled, isFalse);
|
expect(showBottomSheetThenCalled, isFalse);
|
||||||
|
|
||||||
// Tap on the bottom sheet itself to dismiss it.
|
// Tap on the bottom sheet itself, it should not be dismissed
|
||||||
await tester.tap(find.text('BottomSheet'));
|
await tester.tap(find.text('BottomSheet'));
|
||||||
await tester.pump(); // bottom sheet dismiss animation starts
|
await tester.pumpAndSettle();
|
||||||
expect(showBottomSheetThenCalled, isTrue);
|
expect(find.text('BottomSheet'), findsOneWidget);
|
||||||
await tester.pump(const Duration(seconds: 1)); // last frame of animation (sheet is entirely off-screen, but still present)
|
expect(showBottomSheetThenCalled, isFalse);
|
||||||
await tester.pump(const Duration(seconds: 1)); // frame after the animation (sheet has been removed)
|
});
|
||||||
|
|
||||||
|
testWidgets('Tapping outside a modal BottomSheet should dismiss it', (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);
|
expect(find.text('BottomSheet'), findsNothing);
|
||||||
|
|
||||||
showBottomSheetThenCalled = false;
|
bool showBottomSheetThenCalled = false;
|
||||||
showModalBottomSheet<void>(
|
showModalBottomSheet<void>(
|
||||||
context: savedContext,
|
context: savedContext,
|
||||||
builder: (BuildContext context) => const Text('BottomSheet'),
|
builder: (BuildContext context) => const Text('BottomSheet'),
|
||||||
).then<void>((void value) {
|
).then<void>((void value) {
|
||||||
showBottomSheetThenCalled = true;
|
showBottomSheetThenCalled = true;
|
||||||
});
|
});
|
||||||
await tester.pump(); // bottom sheet show animation starts
|
|
||||||
await tester.pump(const Duration(seconds: 1)); // animation done
|
await tester.pumpAndSettle();
|
||||||
expect(find.text('BottomSheet'), findsOneWidget);
|
expect(find.text('BottomSheet'), findsOneWidget);
|
||||||
expect(showBottomSheetThenCalled, isFalse);
|
expect(showBottomSheetThenCalled, isFalse);
|
||||||
|
|
@ -406,8 +406,8 @@ void main() {
|
|||||||
await tester.pumpAndSettle();
|
await tester.pumpAndSettle();
|
||||||
expect(find.text('modal bottom sheet'), findsOneWidget);
|
expect(find.text('modal bottom sheet'), findsOneWidget);
|
||||||
|
|
||||||
// Dismiss the modal bottomSheet
|
// Dismiss the modal bottomSheet by tapping above the sheet
|
||||||
await tester.tap(find.text('modal bottom sheet'));
|
await tester.tapAt(const Offset(20.0, 20.0));
|
||||||
await tester.pumpAndSettle();
|
await tester.pumpAndSettle();
|
||||||
expect(find.text('modal bottom sheet'), findsNothing);
|
expect(find.text('modal bottom sheet'), findsNothing);
|
||||||
expect(find.text('showModalBottomSheet'), findsOneWidget);
|
expect(find.text('showModalBottomSheet'), findsOneWidget);
|
||||||
|
Loading…
Reference in New Issue
Block a user