Unverified Commit 6dc9bf0a authored by Michael Goderbauer's avatar Michael Goderbauer Committed by GitHub

Fix curve for popping hero (#39844)

parent 0de6fc82
...@@ -413,6 +413,7 @@ class _HeroFlightManifest { ...@@ -413,6 +413,7 @@ class _HeroFlightManifest {
@required this.createRectTween, @required this.createRectTween,
@required this.shuttleBuilder, @required this.shuttleBuilder,
@required this.isUserGestureTransition, @required this.isUserGestureTransition,
@required this.isDiverted,
}) : assert(fromHero.widget.tag == toHero.widget.tag); }) : assert(fromHero.widget.tag == toHero.widget.tag);
final HeroFlightDirection type; final HeroFlightDirection type;
...@@ -425,6 +426,7 @@ class _HeroFlightManifest { ...@@ -425,6 +426,7 @@ class _HeroFlightManifest {
final CreateRectTween createRectTween; final CreateRectTween createRectTween;
final HeroFlightShuttleBuilder shuttleBuilder; final HeroFlightShuttleBuilder shuttleBuilder;
final bool isUserGestureTransition; final bool isUserGestureTransition;
final bool isDiverted;
Object get tag => fromHero.widget.tag; Object get tag => fromHero.widget.tag;
...@@ -432,6 +434,7 @@ class _HeroFlightManifest { ...@@ -432,6 +434,7 @@ class _HeroFlightManifest {
return CurvedAnimation( return CurvedAnimation(
parent: (type == HeroFlightDirection.push) ? toRoute.animation : fromRoute.animation, parent: (type == HeroFlightDirection.push) ? toRoute.animation : fromRoute.animation,
curve: Curves.fastOutSlowIn, curve: Curves.fastOutSlowIn,
reverseCurve: isDiverted ? null : Curves.fastOutSlowIn.flipped,
); );
} }
...@@ -805,6 +808,7 @@ class HeroController extends NavigatorObserver { ...@@ -805,6 +808,7 @@ class HeroController extends NavigatorObserver {
if (toHeroes[tag] != null) { if (toHeroes[tag] != null) {
final HeroFlightShuttleBuilder fromShuttleBuilder = fromHeroes[tag].widget.flightShuttleBuilder; final HeroFlightShuttleBuilder fromShuttleBuilder = fromHeroes[tag].widget.flightShuttleBuilder;
final HeroFlightShuttleBuilder toShuttleBuilder = toHeroes[tag].widget.flightShuttleBuilder; final HeroFlightShuttleBuilder toShuttleBuilder = toHeroes[tag].widget.flightShuttleBuilder;
final bool isDiverted = _flights[tag] != null;
final _HeroFlightManifest manifest = _HeroFlightManifest( final _HeroFlightManifest manifest = _HeroFlightManifest(
type: flightType, type: flightType,
...@@ -818,9 +822,10 @@ class HeroController extends NavigatorObserver { ...@@ -818,9 +822,10 @@ class HeroController extends NavigatorObserver {
shuttleBuilder: shuttleBuilder:
toShuttleBuilder ?? fromShuttleBuilder ?? _defaultHeroFlightShuttleBuilder, toShuttleBuilder ?? fromShuttleBuilder ?? _defaultHeroFlightShuttleBuilder,
isUserGestureTransition: isUserGestureTransition, isUserGestureTransition: isUserGestureTransition,
isDiverted: isDiverted,
); );
if (_flights[tag] != null) if (isDiverted)
_flights[tag].divert(manifest); _flights[tag].divert(manifest);
else else
_flights[tag] = _HeroFlight(_handleFlightEnded)..start(manifest); _flights[tag] = _HeroFlight(_handleFlightEnded)..start(manifest);
......
...@@ -1254,17 +1254,17 @@ Future<void> main() async { ...@@ -1254,17 +1254,17 @@ Future<void> main() async {
await tester.pump(duration * 0.25); await tester.pump(duration * 0.25);
actualHeroCenter = tester.getCenter(find.byKey(firstKey)); actualHeroCenter = tester.getCenter(find.byKey(firstKey));
predictedHeroCenter = popCenterTween.lerp(curve.flipped.transform(0.25)); predictedHeroCenter = popCenterTween.lerp(curve.transform(0.25));
expect(actualHeroCenter, within<Offset>(distance: epsilon, from: predictedHeroCenter)); expect(actualHeroCenter, within<Offset>(distance: epsilon, from: predictedHeroCenter));
await tester.pump(duration * 0.25); await tester.pump(duration * 0.25);
actualHeroCenter = tester.getCenter(find.byKey(firstKey)); actualHeroCenter = tester.getCenter(find.byKey(firstKey));
predictedHeroCenter = popCenterTween.lerp(curve.flipped.transform(0.5)); predictedHeroCenter = popCenterTween.lerp(curve.transform(0.5));
expect(actualHeroCenter, within<Offset>(distance: epsilon, from: predictedHeroCenter)); expect(actualHeroCenter, within<Offset>(distance: epsilon, from: predictedHeroCenter));
await tester.pump(duration * 0.25); await tester.pump(duration * 0.25);
actualHeroCenter = tester.getCenter(find.byKey(firstKey)); actualHeroCenter = tester.getCenter(find.byKey(firstKey));
predictedHeroCenter = popCenterTween.lerp(curve.flipped.transform(0.75)); predictedHeroCenter = popCenterTween.lerp(curve.transform(0.75));
expect(actualHeroCenter, within<Offset>(distance: epsilon, from: predictedHeroCenter)); expect(actualHeroCenter, within<Offset>(distance: epsilon, from: predictedHeroCenter));
await tester.pumpAndSettle(); await tester.pumpAndSettle();
...@@ -1375,17 +1375,17 @@ Future<void> main() async { ...@@ -1375,17 +1375,17 @@ Future<void> main() async {
await tester.pump(duration * 0.25); await tester.pump(duration * 0.25);
actualHeroRect = tester.getRect(find.byKey(firstKey)); actualHeroRect = tester.getRect(find.byKey(firstKey));
predictedHeroRect = popRectTween.lerp(curve.flipped.transform(0.25)); predictedHeroRect = popRectTween.lerp(curve.transform(0.25));
expect(actualHeroRect, within<Rect>(distance: epsilon, from: predictedHeroRect)); expect(actualHeroRect, within<Rect>(distance: epsilon, from: predictedHeroRect));
await tester.pump(duration * 0.25); await tester.pump(duration * 0.25);
actualHeroRect = tester.getRect(find.byKey(firstKey)); actualHeroRect = tester.getRect(find.byKey(firstKey));
predictedHeroRect = popRectTween.lerp(curve.flipped.transform(0.5)); predictedHeroRect = popRectTween.lerp(curve.transform(0.5));
expect(actualHeroRect, within<Rect>(distance: epsilon, from: predictedHeroRect)); expect(actualHeroRect, within<Rect>(distance: epsilon, from: predictedHeroRect));
await tester.pump(duration * 0.25); await tester.pump(duration * 0.25);
actualHeroRect = tester.getRect(find.byKey(firstKey)); actualHeroRect = tester.getRect(find.byKey(firstKey));
predictedHeroRect = popRectTween.lerp(curve.flipped.transform(0.75)); predictedHeroRect = popRectTween.lerp(curve.transform(0.75));
expect(actualHeroRect, within<Rect>(distance: epsilon, from: predictedHeroRect)); expect(actualHeroRect, within<Rect>(distance: epsilon, from: predictedHeroRect));
await tester.pumpAndSettle(); await tester.pumpAndSettle();
...@@ -2255,4 +2255,83 @@ Future<void> main() async { ...@@ -2255,4 +2255,83 @@ Future<void> main() async {
moreOrLessEquals(tester.getTopLeft(find.text('1')).dx, epsilon: 0.01) moreOrLessEquals(tester.getTopLeft(find.text('1')).dx, epsilon: 0.01)
); );
}); });
testWidgets('popped hero uses fastOutSlowIn curve', (WidgetTester tester) async {
final Key container1 = UniqueKey();
final Key container2 = UniqueKey();
final GlobalKey<NavigatorState> navigator = GlobalKey<NavigatorState>();
final Animatable<Size> tween = SizeTween(
begin: const Size(200, 200),
end: const Size(100, 100),
).chain(CurveTween(curve: Curves.fastOutSlowIn));
await tester.pumpWidget(
MaterialApp(
navigatorKey: navigator,
home: Scaffold(
body: Center(
child: Hero(
tag: 'test',
createRectTween: (Rect begin, Rect end) {
return RectTween(begin: begin, end: end);
},
child: Container(
key: container1,
height: 100,
width: 100,
),
),
),
),
),
);
final Size originalSize = tester.getSize(find.byKey(container1));
expect(originalSize, const Size(100, 100));
navigator.currentState.push(MaterialPageRoute<void>(builder: (BuildContext context) {
return Scaffold(
body: Center(
child: Hero(
tag: 'test',
createRectTween: (Rect begin, Rect end) {
return RectTween(begin: begin, end: end);
},
child: Container(
key: container2,
height: 200,
width: 200,
),
),
),
);
}));
await tester.pumpAndSettle();
final Size newSize = tester.getSize(find.byKey(container2));
expect(newSize, const Size(200, 200));
navigator.currentState.pop();
await tester.pump();
// Jump 25% into the transition (total length = 300ms)
await tester.pump(const Duration(milliseconds: 75)); // 25% of 300ms
Size heroSize = tester.getSize(find.byKey(container1));
expect(heroSize, tween.transform(0.25));
// Jump to 50% into the transition.
await tester.pump(const Duration(milliseconds: 75)); // 25% of 300ms
heroSize = tester.getSize(find.byKey(container1));
expect(heroSize, tween.transform(0.50));
// Jump to 75% into the transition.
await tester.pump(const Duration(milliseconds: 75)); // 25% of 300ms
heroSize = tester.getSize(find.byKey(container1));
expect(heroSize, tween.transform(0.75));
// Jump to 100% into the transition.
await tester.pump(const Duration(milliseconds: 75)); // 25% of 300ms
heroSize = tester.getSize(find.byKey(container1));
expect(heroSize, tween.transform(1.0));
});
} }
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