From 5eaaad41fb494e5b805e89f48a53d2a0b0b4e30e Mon Sep 17 00:00:00 2001 From: chunhtai <47866232+chunhtai@users.noreply.github.com> Date: Fri, 5 Jun 2020 15:40:28 -0700 Subject: [PATCH] =?UTF-8?q?fix=20cupertino=20page=20route=20dismisses=20he?= =?UTF-8?q?ro=20transition=20when=20swipe=20to=20the=20=E2=80=A6=20(#58024?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix cupertino page route dismisses hero transition when swipe to the edge * add more comment * addressing comments --- packages/flutter/lib/src/widgets/heroes.dart | 8 +++ .../flutter/test/cupertino/route_test.dart | 70 +++++++++++++++++++ 2 files changed, 78 insertions(+) diff --git a/packages/flutter/lib/src/widgets/heroes.dart b/packages/flutter/lib/src/widgets/heroes.dart index 7253e7bbf99..ab64df09525 100644 --- a/packages/flutter/lib/src/widgets/heroes.dart +++ b/packages/flutter/lib/src/widgets/heroes.dart @@ -533,6 +533,14 @@ class _HeroFlight { } void _handleAnimationUpdate(AnimationStatus status) { + // The animation will not finish until the user lifts their finger, so we + // should ignore the status update if the gesture is in progress. + // + // This also relies on the animation to update its status at the end of the + // gesture. See the _CupertinoBackGestureController.dragEnd for how + // cupertino page route achieves that. + if (manifest.fromRoute?.navigator?.userGestureInProgress == true) + return; if (status == AnimationStatus.completed || status == AnimationStatus.dismissed) { _proxyAnimation.parent = null; diff --git a/packages/flutter/test/cupertino/route_test.dart b/packages/flutter/test/cupertino/route_test.dart index 2215f70d55c..bd083fa3be4 100644 --- a/packages/flutter/test/cupertino/route_test.dart +++ b/packages/flutter/test/cupertino/route_test.dart @@ -1133,6 +1133,76 @@ void main() { expect(nestedObserver.popupCount, 0); }); + testWidgets('back swipe to screen edges does not dismiss the hero animation', (WidgetTester tester) async { + final GlobalKey navigator = GlobalKey(); + final UniqueKey container = UniqueKey(); + await tester.pumpWidget(CupertinoApp( + navigatorKey: navigator, + routes: { + '/': (BuildContext context) { + return CupertinoPageScaffold( + child: Center( + child: Hero( + tag: 'tag', + transitionOnUserGestures: true, + child: Container(key: container, height: 150.0, width: 150.0) + ), + ) + ); + }, + '/page2': (BuildContext context) { + return CupertinoPageScaffold( + child: Center( + child: Padding( + padding: const EdgeInsets.fromLTRB(100.0, 0.0, 0.0, 0.0), + child: Hero( + tag: 'tag', + transitionOnUserGestures: true, + child: Container(key: container, height: 150.0, width: 150.0) + ) + ), + ) + ); + } + }, + )); + + RenderBox box = tester.renderObject(find.byKey(container)) as RenderBox; + final double initialPosition = box.localToGlobal(Offset.zero).dx; + + navigator.currentState.pushNamed('/page2'); + await tester.pumpAndSettle(); + box = tester.renderObject(find.byKey(container)) as RenderBox; + final double finalPosition = box.localToGlobal(Offset.zero).dx; + + final TestGesture gesture = await tester.startGesture(const Offset(5, 300)); + await gesture.moveBy(const Offset(200, 0)); + await tester.pump(); + box = tester.renderObject(find.byKey(container)) as RenderBox; + final double firstPosition = box.localToGlobal(Offset.zero).dx; + // Checks the hero is in-transit. + expect(finalPosition, greaterThan(firstPosition)); + expect(firstPosition, greaterThan(initialPosition)); + + // Goes back to final position. + await gesture.moveBy(const Offset(-200, 0)); + await tester.pump(); + box = tester.renderObject(find.byKey(container)) as RenderBox; + final double secondPosition = box.localToGlobal(Offset.zero).dx; + // There will be a small difference. + expect(finalPosition - secondPosition, lessThan(0.001)); + + await gesture.moveBy(const Offset(400, 0)); + await tester.pump(); + box = tester.renderObject(find.byKey(container)) as RenderBox; + final double thirdPosition = box.localToGlobal(Offset.zero).dx; + // Checks the hero is still in-transit and moves further away from the first + // position. + expect(finalPosition, greaterThan(thirdPosition)); + expect(thirdPosition, greaterThan(initialPosition)); + expect(firstPosition, greaterThan(thirdPosition)); + }); + testWidgets('showCupertinoModalPopup uses nested navigator if useRootNavigator is false', (WidgetTester tester) async { final PopupObserver rootObserver = PopupObserver(); final PopupObserver nestedObserver = PopupObserver();