diff --git a/packages/flutter/lib/src/widgets/implicit_animations.dart b/packages/flutter/lib/src/widgets/implicit_animations.dart index 4e74a904e3..5aa13f8d47 100644 --- a/packages/flutter/lib/src/widgets/implicit_animations.dart +++ b/packages/flutter/lib/src/widgets/implicit_animations.dart @@ -111,12 +111,21 @@ class Matrix4Tween extends Tween { Matrix4 lerp(double t) { assert(begin != null); assert(end != null); - // TODO(abarth): We should use [Matrix4.decompose] and animate the - // decomposed parameters instead of just animating the translation. - final Vector3 beginT = begin.getTranslation(); - final Vector3 endT = end.getTranslation(); - final Vector3 lerpT = beginT*(1.0-t) + endT*t; - return new Matrix4.identity()..translate(lerpT); + final Vector3 beginTranslation = new Vector3.zero(); + final Vector3 endTranslation = new Vector3.zero(); + final Quaternion beginRotation = new Quaternion.identity(); + final Quaternion endRotation = new Quaternion.identity(); + final Vector3 beginScale = new Vector3.zero(); + final Vector3 endScale = new Vector3.zero(); + begin.decompose(beginTranslation, beginRotation, beginScale); + end.decompose(endTranslation, endRotation, endScale); + final Vector3 lerpTranslation = + beginTranslation * (1.0 - t) + endTranslation * t; + // TODO(alangardner): Implement slerp for constant rotation + final Quaternion lerpRotation = + (beginRotation.scaled(1.0 - t) + endRotation.scaled(t)).normalized(); + final Vector3 lerpScale = beginScale * (1.0 - t) + endScale * t; + return new Matrix4.compose(lerpTranslation, lerpRotation, lerpScale); } } diff --git a/packages/flutter/test/animation/tween_test.dart b/packages/flutter/test/animation/tween_test.dart index e8a9a97ff7..72364f4232 100644 --- a/packages/flutter/test/animation/tween_test.dart +++ b/packages/flutter/test/animation/tween_test.dart @@ -5,6 +5,7 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:flutter/animation.dart'; import 'package:flutter/widgets.dart'; +import 'package:vector_math/vector_math_64.dart'; void main() { test('Can chain tweens', () { @@ -49,4 +50,26 @@ void main() { expect(tween.lerp(0.5), equals(Rect.lerp(a, b, 0.5))); expect(tween, hasOneLineDescription); }); + + test('Matrix4Tween', () { + final Matrix4 a = new Matrix4.identity(); + final Matrix4 b = a.clone()..translate(6.0, -8.0, 0.0)..scale(0.5, 1.0, 5.0); + final Matrix4Tween tween = new Matrix4Tween(begin: a, end: b); + expect(tween.lerp(0.0), equals(a)); + expect(tween.lerp(1.0), equals(b)); + expect( + tween.lerp(0.5), + equals(a.clone()..translate(3.0, -4.0, 0.0)..scale(0.75, 1.0, 3.0)) + ); + final Matrix4 c = a.clone()..rotateZ(1.0); + final Matrix4Tween rotationTween = new Matrix4Tween(begin: a, end: c); + expect(rotationTween.lerp(0.0), equals(a)); + expect(rotationTween.lerp(1.0), equals(c)); + expect( + rotationTween.lerp(0.5).absoluteError( + a.clone()..rotateZ(0.5) + ), + moreOrLessEquals(0.0) + ); + }); }