Unverified Commit 46b0797b authored by Zain Ur Rehman's avatar Zain Ur Rehman Committed by GitHub

Expose AnimationController property to showBottomSheet/showModalBottomSheet (#72541)

* Expose AnimationController property to showBottomSheet/showModalBottomSheet (#72541)
ong <shihaohong@google.com>
Co-authored-by: 's avatarKate Lovett <katelovett@google.com>
Co-authored-by: 's avatarShi-Hao Hong <shihaohong@google.com>
parent 32db0fe7
......@@ -431,6 +431,7 @@ class _ModalBottomSheetRoute<T> extends PopupRoute<T> {
this.enableDrag = true,
required this.isScrollControlled,
RouteSettings? settings,
this.transitionAnimationController,
}) : assert(isScrollControlled != null),
assert(isDismissible != null),
assert(enableDrag != null),
......@@ -446,6 +447,7 @@ class _ModalBottomSheetRoute<T> extends PopupRoute<T> {
final Color? modalBarrierColor;
final bool isDismissible;
final bool enableDrag;
final AnimationController? transitionAnimationController;
@override
Duration get transitionDuration => _bottomSheetEnterDuration;
......@@ -467,7 +469,7 @@ class _ModalBottomSheetRoute<T> extends PopupRoute<T> {
@override
AnimationController createAnimationController() {
assert(_animationController == null);
_animationController = BottomSheet.createAnimationController(navigator!.overlay!);
_animationController = transitionAnimationController ?? BottomSheet.createAnimationController(navigator!.overlay!);
return _animationController!;
}
......@@ -588,10 +590,13 @@ class _BottomSheetSuspendedCurve extends ParametricCurve<double> {
/// The [enableDrag] parameter specifies whether the bottom sheet can be
/// dragged up and down and dismissed by swiping downwards.
///
/// The optional [backgroundColor], [elevation], [shape], and [clipBehavior]
/// The optional [backgroundColor], [elevation], [shape], [clipBehavior] and [transitionAnimationController]
/// parameters can be passed in to customize the appearance and behavior of
/// modal bottom sheets.
///
/// The [transitionAnimationController] controls the bottom sheet's entrance and
/// exit animations if provided.
///
/// The optional `routeSettings` parameter sets the [RouteSettings] of the modal bottom sheet
/// sheet. This is particularly useful in the case that a user wants to observe
/// [PopupRoute]s within a [NavigatorObserver].
......@@ -662,6 +667,7 @@ Future<T?> showModalBottomSheet<T>({
bool isDismissible = true,
bool enableDrag = true,
RouteSettings? routeSettings,
AnimationController? transitionAnimationController,
}) {
assert(context != null);
assert(builder != null);
......@@ -686,6 +692,7 @@ Future<T?> showModalBottomSheet<T>({
modalBarrierColor: barrierColor,
enableDrag: enableDrag,
settings: routeSettings,
transitionAnimationController: transitionAnimationController,
));
}
......@@ -695,7 +702,7 @@ Future<T?> showModalBottomSheet<T>({
/// Returns a controller that can be used to close and otherwise manipulate the
/// bottom sheet.
///
/// The optional [backgroundColor], [elevation], [shape], and [clipBehavior]
/// The optional [backgroundColor], [elevation], [shape], [clipBehavior] and [transitionAnimationController]
/// parameters can be passed in to customize the appearance and behavior of
/// persistent bottom sheets.
///
......@@ -735,6 +742,7 @@ PersistentBottomSheetController<T> showBottomSheet<T>({
double? elevation,
ShapeBorder? shape,
Clip? clipBehavior,
AnimationController? transitionAnimationController,
}) {
assert(context != null);
assert(builder != null);
......@@ -746,5 +754,6 @@ PersistentBottomSheetController<T> showBottomSheet<T>({
elevation: elevation,
shape: shape,
clipBehavior: clipBehavior,
transitionAnimationController: transitionAnimationController,
);
}
......@@ -2634,6 +2634,7 @@ class ScaffoldState extends State<Scaffold> with TickerProviderStateMixin, Resto
double? elevation,
ShapeBorder? shape,
Clip? clipBehavior,
AnimationController? transitionAnimationController,
}) {
assert(() {
if (widget.bottomSheet != null) {
......@@ -2648,7 +2649,7 @@ class ScaffoldState extends State<Scaffold> with TickerProviderStateMixin, Resto
assert(debugCheckHasMediaQuery(context));
_closeCurrentBottomSheet();
final AnimationController controller = BottomSheet.createAnimationController(this)..forward();
final AnimationController controller = (transitionAnimationController ?? BottomSheet.createAnimationController(this))..forward();
setState(() {
_currentBottomSheet = _buildBottomSheet<T>(
builder,
......
......@@ -727,6 +727,127 @@ void main() {
expect(retrievedRouteSettings, routeSettings);
});
testWidgets('Verify showModalBottomSheet use AnimationController if provided.', (WidgetTester tester) async {
const Key tapTarget = Key('tap-target');
await tester.pumpWidget(MaterialApp(
home: Scaffold(
body: Builder(
builder: (BuildContext context) {
return GestureDetector(
onTap: () {
showModalBottomSheet<void>(
context: context,
// The default duration and reverseDuration is 1 second
transitionAnimationController: AnimationController(
vsync: const TestVSync(),
duration: const Duration(seconds: 2),
reverseDuration: const Duration(seconds: 2),
),
builder: (BuildContext context) {
return Container(
child: const Text('BottomSheet'),
);
},
);
},
behavior: HitTestBehavior.opaque,
child: Container(
height: 100.0,
width: 100.0,
key: tapTarget,
),
);
},
),
),
));
expect(find.text('BottomSheet'), findsNothing);
await tester.tap(find.byKey(tapTarget)); // Opening animation will start after tapping
await tester.pump();
expect(find.text('BottomSheet'), findsOneWidget);
await tester.pump(const Duration(milliseconds: 2000));
expect(find.text('BottomSheet'), findsOneWidget);
// Tapping above the bottom sheet to dismiss it.
await tester.tapAt(const Offset(20.0, 20.0)); // Closing animation will start after tapping
await tester.pump();
expect(find.text('BottomSheet'), findsOneWidget);
await tester.pump(const Duration(milliseconds: 2000));
// The bottom sheet should still be present at the very end of the animation.
expect(find.text('BottomSheet'), findsOneWidget);
await tester.pump(const Duration(milliseconds: 1));
// The bottom sheet should not be showing any longer.
expect(find.text('BottomSheet'), findsNothing);
});
testWidgets('Verify persistence BottomSheet use AnimationController if provided.', (WidgetTester tester) async {
const Key tapTarget = Key('tap-target');
const Key tapTargetToClose = Key('tap-target-to-close');
await tester.pumpWidget(MaterialApp(
home: Scaffold(
body: Builder(
builder: (BuildContext context) {
return GestureDetector(
onTap: () {
showBottomSheet<void>(
context: context,
// The default duration and reverseDuration is 1 second
transitionAnimationController: AnimationController(
vsync: const TestVSync(),
duration: const Duration(seconds: 2),
reverseDuration: const Duration(seconds: 2),
),
builder: (BuildContext context) {
return Container(
child: MaterialButton(
child: const Text('BottomSheet'),
onPressed: () => Navigator.pop(context),
key: tapTargetToClose,
),
);
},
);
},
behavior: HitTestBehavior.opaque,
child: Container(
height: 100.0,
width: 100.0,
key: tapTarget,
),
);
},
),
),
));
expect(find.text('BottomSheet'), findsNothing);
await tester.tap(find.byKey(tapTarget)); // Opening animation will start after tapping
await tester.pump();
expect(find.text('BottomSheet'), findsOneWidget);
await tester.pump(const Duration(milliseconds: 2000));
expect(find.text('BottomSheet'), findsOneWidget);
// Tapping button on the bottom sheet to dismiss it.
await tester.tap(find.byKey(tapTargetToClose)); // Closing animation will start after tapping
await tester.pump();
expect(find.text('BottomSheet'), findsOneWidget);
await tester.pump(const Duration(milliseconds: 2000));
// The bottom sheet should still be present at the very end of the animation.
expect(find.text('BottomSheet'), findsOneWidget);
await tester.pump(const Duration(milliseconds: 1));
// The bottom sheet should not be showing any longer.
expect(find.text('BottomSheet'), findsNothing);
});
testWidgets('showModalBottomSheet should move along on-screen keyboard',
(WidgetTester tester) async {
late BuildContext savedContext;
......
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