@@ -79,8 +79,8 @@ class AnimationDelegateImpl extends NSObject implements CAAnimationDelegate {
7979 targetStyle [ setLocal ? widthProperty . name : widthProperty . keyframe ] = value ;
8080 break ;
8181 case Properties . scale :
82- targetStyle [ setLocal ? scaleXProperty . name : scaleXProperty . keyframe ] = value . x === 0 ? 1e-6 : value . x ;
83- targetStyle [ setLocal ? scaleYProperty . name : scaleYProperty . keyframe ] = value . y === 0 ? 1e-6 : value . y ;
82+ targetStyle [ setLocal ? scaleXProperty . name : scaleXProperty . keyframe ] = value . x === 0 ? 0.001 : value . x ;
83+ targetStyle [ setLocal ? scaleYProperty . name : scaleYProperty . keyframe ] = value . y === 0 ? 0.001 : value . y ;
8484 break ;
8585 case _transform :
8686 if ( value [ Properties . translate ] !== undefined ) {
@@ -95,8 +95,8 @@ class AnimationDelegateImpl extends NSObject implements CAAnimationDelegate {
9595 if ( value [ Properties . scale ] !== undefined ) {
9696 const x = value [ Properties . scale ] . x ;
9797 const y = value [ Properties . scale ] . y ;
98- targetStyle [ setLocal ? scaleXProperty . name : scaleXProperty . keyframe ] = x === 0 ? 1e-6 : x ;
99- targetStyle [ setLocal ? scaleYProperty . name : scaleYProperty . keyframe ] = y === 0 ? 1e-6 : y ;
98+ targetStyle [ setLocal ? scaleXProperty . name : scaleXProperty . keyframe ] = x === 0 ? 0.001 : x ;
99+ targetStyle [ setLocal ? scaleYProperty . name : scaleYProperty . keyframe ] = y === 0 ? 0.001 : y ;
100100 }
101101 break ;
102102 }
@@ -309,6 +309,7 @@ export class Animation extends AnimationBase {
309309 const parent = view . parent as View ;
310310
311311 let propertyNameToAnimate = animation . property ;
312+ let subPropertyNameToAnimate ;
312313 let toValue = animation . value ;
313314 let fromValue ;
314315 if ( nativeView ) {
@@ -334,6 +335,8 @@ export class Animation extends AnimationBase {
334335 } ;
335336 fromValue = nativeView . layer . opacity ;
336337 break ;
338+ // In the case of rotation, avoid animating affine transform directly as it will animate to the closest result
339+ // that is visually the same. For example, 0 -> 360 will leave view as is.
337340 case Properties . rotate :
338341 animation . _originalValue = {
339342 x : view . rotateX ,
@@ -346,9 +349,30 @@ export class Animation extends AnimationBase {
346349 style [ setLocal ? rotateYProperty . name : rotateYProperty . keyframe ] = value . y ;
347350 } ;
348351
349- propertyNameToAnimate = 'transform' ;
350- fromValue = NSValue . valueWithCATransform3D ( nativeView . layer . transform ) ;
351- toValue = NSValue . valueWithCATransform3D ( iosHelper . applyRotateTransform ( nativeView . layer . transform , toValue . x , toValue . y , toValue . z ) ) ;
352+ propertyNameToAnimate = 'transform.rotation' ;
353+ subPropertyNameToAnimate = [ 'x' , 'y' , 'z' ] ;
354+ fromValue = {
355+ x : nativeView . layer . valueForKeyPath ( 'transform.rotation.x' ) ,
356+ y : nativeView . layer . valueForKeyPath ( 'transform.rotation.y' ) ,
357+ z : nativeView . layer . valueForKeyPath ( 'transform.rotation.z' ) ,
358+ } ;
359+
360+ if ( animation . target . rotateX !== undefined && animation . target . rotateX !== 0 && Math . floor ( toValue / 360 ) - toValue / 360 === 0 ) {
361+ fromValue . x = ( animation . target . rotateX * Math . PI ) / 180 ;
362+ }
363+ if ( animation . target . rotateY !== undefined && animation . target . rotateY !== 0 && Math . floor ( toValue / 360 ) - toValue / 360 === 0 ) {
364+ fromValue . y = ( animation . target . rotateY * Math . PI ) / 180 ;
365+ }
366+ if ( animation . target . rotate !== undefined && animation . target . rotate !== 0 && Math . floor ( toValue / 360 ) - toValue / 360 === 0 ) {
367+ fromValue . z = ( animation . target . rotate * Math . PI ) / 180 ;
368+ }
369+
370+ // Respect only value.z for back-compat until 3D rotations are implemented
371+ toValue = {
372+ x : ( toValue . x * Math . PI ) / 180 ,
373+ y : ( toValue . y * Math . PI ) / 180 ,
374+ z : ( toValue . z * Math . PI ) / 180 ,
375+ } ;
352376 break ;
353377 case Properties . translate :
354378 animation . _originalValue = {
@@ -365,10 +389,10 @@ export class Animation extends AnimationBase {
365389 break ;
366390 case Properties . scale :
367391 if ( toValue . x === 0 ) {
368- toValue . x = 1e-6 ;
392+ toValue . x = 0.001 ;
369393 }
370394 if ( toValue . y === 0 ) {
371- toValue . y = 1e-6 ;
395+ toValue . y = 0.001 ;
372396 }
373397 animation . _originalValue = { x : view . scaleX , y : view . scaleY } ;
374398 animation . _propertyResetCallback = ( value , valueSource ) => {
@@ -451,6 +475,7 @@ export class Animation extends AnimationBase {
451475 return {
452476 propertyNameToAnimate : propertyNameToAnimate ,
453477 fromValue : fromValue ,
478+ subPropertiesToAnimate : subPropertyNameToAnimate ,
454479 toValue : toValue ,
455480 duration : duration ,
456481 repeatCount : repeatCount ,
@@ -496,10 +521,10 @@ export class Animation extends AnimationBase {
496521 }
497522
498523 private static _createGroupAnimation ( args : AnimationInfo , animation : PropertyAnimation ) {
499- const animations = NSMutableArray . alloc < CAAnimation > ( ) . initWithCapacity ( args . subPropertiesToAnimate . length ) ;
500524 const groupAnimation = CAAnimationGroup . new ( ) ;
501- groupAnimation . duration = args . duration ;
525+ const animations = NSMutableArray . alloc < CAAnimation > ( ) . initWithCapacity ( args . subPropertiesToAnimate . length ) ;
502526
527+ groupAnimation . duration = args . duration ;
503528 if ( args . repeatCount !== undefined ) {
504529 groupAnimation . repeatCount = args . repeatCount ;
505530 }
@@ -651,30 +676,16 @@ export class Animation extends AnimationBase {
651676 }
652677
653678 if ( value [ Properties . scale ] !== undefined ) {
654- const x = value [ Properties . scale ] . x || 1e-6 ;
655- const y = value [ Properties . scale ] . y || 1e-6 ;
656- result = CATransform3DScale ( result , x , y , 1 ) ;
657- }
658-
659- if ( value [ Properties . rotate ] !== undefined ) {
660- const x = value [ Properties . rotate ] . x ;
661- const y = value [ Properties . rotate ] . y ;
662- const z = value [ Properties . rotate ] . z ;
663- const perspective = animation . target . perspective || 300 ;
664-
665- // Set perspective in case of rotation since we use z
666- if ( x || y ) {
667- result . m34 = - 1 / perspective ;
668- }
669-
670- result = iosHelper . applyRotateTransform ( result , x , y , z ) ;
679+ const x = value [ Properties . scale ] . x ;
680+ const y = value [ Properties . scale ] . y ;
681+ result = CATransform3DScale ( result , x === 0 ? 0.001 : x , y === 0 ? 0.001 : y , 1 ) ;
671682 }
672683
673684 return result ;
674685 }
675686
676687 private static _isAffineTransform ( property : string ) : boolean {
677- return property === _transform || property === Properties . translate || property === Properties . scale || property === Properties . rotate ;
688+ return property === _transform || property === Properties . translate || property === Properties . scale ;
678689 }
679690
680691 private static _canBeMerged ( animation1 : PropertyAnimation , animation2 : PropertyAnimation ) {
@@ -941,8 +952,7 @@ function calculateTransform(view: View): CATransform3D {
941952 // Order is important: translate, rotate, scale
942953 let expectedTransform = new CATransform3D ( CATransform3DIdentity ) ;
943954
944- // TODO: Add perspective property to transform animations (not just rotation)
945- // Set perspective in case of rotation since we use z
955+ // Only set perspective if there is 3D rotation
946956 if ( view . rotateX || view . rotateY ) {
947957 expectedTransform . m34 = - 1 / perspective ;
948958 }
0 commit comments