From c8c0be76846446124ce4cb27f59dda99d4898731 Mon Sep 17 00:00:00 2001 From: Manol Donev Date: Tue, 16 Oct 2018 15:37:57 +0300 Subject: [PATCH] refactor: restore animators api usage (#6403) --- .../navigation/custom-transition.android.ts | 29 ++- tns-core-modules/ui/frame/fragment.android.ts | 5 +- .../ui/frame/fragment.transitions.android.ts | 181 ++++++++--------- .../ui/frame/fragment.transitions.d.ts | 2 +- tns-core-modules/ui/frame/frame.android.ts | 14 +- tns-core-modules/ui/frame/frame.d.ts | 2 +- .../ui/transition/fade-transition.android.ts | 21 +- .../ui/transition/flip-transition.android.ts | 184 +++++++++--------- .../ui/transition/slide-transition.android.ts | 20 +- .../ui/transition/transition.android.ts | 2 +- .../ui/transition/transition.d.ts | 2 +- .../ui/transition/transition.ios.ts | 2 +- 12 files changed, 229 insertions(+), 235 deletions(-) diff --git a/tests/app/navigation/custom-transition.android.ts b/tests/app/navigation/custom-transition.android.ts index d8f1b453d..24434118f 100644 --- a/tests/app/navigation/custom-transition.android.ts +++ b/tests/app/navigation/custom-transition.android.ts @@ -5,9 +5,8 @@ export class CustomTransition extends transition.Transition { super(duration, curve); } - public createAndroidAnimation(transitionType: string): android.view.animation.Animation { - const scaleValues = []; - + public createAndroidAnimator(transitionType: string): android.animation.Animator { + var scaleValues = Array.create("float", 2); switch (transitionType) { case transition.AndroidTransitionType.enter: case transition.AndroidTransitionType.popEnter: @@ -20,22 +19,18 @@ export class CustomTransition extends transition.Transition { scaleValues[1] = 0; break; } - - const animationSet = new android.view.animation.AnimationSet(false); - const duration = this.getDuration(); + var objectAnimators = Array.create(android.animation.Animator, 2); + objectAnimators[0] = android.animation.ObjectAnimator.ofFloat(null, "scaleX", scaleValues); + objectAnimators[1] = android.animation.ObjectAnimator.ofFloat(null, "scaleY", scaleValues); + var animatorSet = new android.animation.AnimatorSet(); + animatorSet.playTogether(objectAnimators); + + var duration = this.getDuration(); if (duration !== undefined) { - animationSet.setDuration(duration); + animatorSet.setDuration(duration); } + animatorSet.setInterpolator(this.getCurve()); - animationSet.setInterpolator(this.getCurve()); - animationSet.addAnimation( - new android.view.animation.ScaleAnimation( - scaleValues[0], - scaleValues[1], - scaleValues[0], - scaleValues[1] - )); - - return animationSet; + return animatorSet; } } diff --git a/tns-core-modules/ui/frame/fragment.android.ts b/tns-core-modules/ui/frame/fragment.android.ts index f659ce0aa..86b3ccc2c 100644 --- a/tns-core-modules/ui/frame/fragment.android.ts +++ b/tns-core-modules/ui/frame/fragment.android.ts @@ -14,8 +14,9 @@ class FragmentClass extends android.support.v4.app.Fragment { this._callbacks.onHiddenChanged(this, hidden, super.onHiddenChanged); } - public onCreateAnimation(transit: number, enter: boolean, nextAnim: number): android.view.animation.Animation { - return this._callbacks.onCreateAnimation(this, transit, enter, nextAnim, super.onCreateAnimation); + public onCreateAnimator(transit: number, enter: boolean, nextAnim: number): android.animation.Animator { + let result = this._callbacks.onCreateAnimator(this, transit, enter, nextAnim, super.onCreateAnimator); + return result; } public onStop(): void { diff --git a/tns-core-modules/ui/frame/fragment.transitions.android.ts b/tns-core-modules/ui/frame/fragment.transitions.android.ts index 3ff499c01..bfb61ea50 100644 --- a/tns-core-modules/ui/frame/fragment.transitions.android.ts +++ b/tns-core-modules/ui/frame/fragment.transitions.android.ts @@ -19,7 +19,7 @@ interface TransitionListener { new(entry: ExpandedEntry, transition: android.transition.Transition): ExpandedTransitionListener; } -interface ExpandedAnimation extends android.view.animation.Animation { +interface ExpandedAnimator extends android.animation.Animator { entry: ExpandedEntry; transitionType?: string; } @@ -35,13 +35,13 @@ interface ExpandedEntry extends BackstackEntry { reenterTransitionListener: ExpandedTransitionListener; returnTransitionListener: ExpandedTransitionListener; - enterAnimation: ExpandedAnimation; - exitAnimation: ExpandedAnimation; - popEnterAnimation: ExpandedAnimation; - popExitAnimation: ExpandedAnimation; + enterAnimator: ExpandedAnimator; + exitAnimator: ExpandedAnimator; + popEnterAnimator: ExpandedAnimator; + popExitAnimator: ExpandedAnimator; - defaultEnterAnimation: ExpandedAnimation; - defaultExitAnimation: ExpandedAnimation; + defaultEnterAnimator: ExpandedAnimator; + defaultExitAnimator: ExpandedAnimator; transition: Transition; transitionName: string; @@ -49,13 +49,14 @@ interface ExpandedEntry extends BackstackEntry { } const sdkVersion = lazy(() => parseInt(device.sdkVersion)); +const intEvaluator = lazy(() => new android.animation.IntEvaluator()); const defaultInterpolator = lazy(() => new android.view.animation.AccelerateDecelerateInterpolator()); export const waitingQueue = new Map>(); export const completedEntries = new Map(); let TransitionListener: TransitionListener; -let AnimationListener: android.view.animation.Animation.AnimationListener; +let AnimationListener: android.animation.Animator.AnimatorListener; export function _setAndroidFragmentTransitions( animated: boolean, @@ -170,39 +171,39 @@ export function _setAndroidFragmentTransitions( printTransitions(newEntry); } -export function _onFragmentCreateAnimation(entry: ExpandedEntry, fragment: android.support.v4.app.Fragment, nextAnim: number, enter: boolean): android.view.animation.Animation { - let animation: android.view.animation.Animation; +export function _onFragmentCreateAnimator(entry: ExpandedEntry, fragment: android.support.v4.app.Fragment, nextAnim: number, enter: boolean): android.animation.Animator { + let animator: android.animation.Animator; switch (nextAnim) { case AnimationType.enterFakeResourceId: - animation = entry.enterAnimation; + animator = entry.enterAnimator; break; case AnimationType.exitFakeResourceId: - animation = entry.exitAnimation; + animator = entry.exitAnimator; break; case AnimationType.popEnterFakeResourceId: - animation = entry.popEnterAnimation; + animator = entry.popEnterAnimator; break; case AnimationType.popExitFakeResourceId: - animation = entry.popExitAnimation; + animator = entry.popExitAnimator; break; } - if (!animation && sdkVersion() >= 21) { + if (!animator && sdkVersion() >= 21) { const view = fragment.getView(); const jsParent = entry.resolvedPage.parent; const parent = view.getParent() || (jsParent && jsParent.nativeViewProtected); const animatedEntries = _getAnimatedEntries(entry.frameId); if (!animatedEntries || !animatedEntries.has(entry)) { if (parent && !(parent).isLaidOut()) { - animation = enter ? entry.defaultEnterAnimation : entry.defaultExitAnimation; + animator = enter ? entry.defaultEnterAnimator : entry.defaultExitAnimator; } } } - return animation; + return animator; } export function _getAnimatedEntries(frameId: number): Set { @@ -312,40 +313,40 @@ function getTransitionListener(entry: ExpandedEntry, transition: android.transit return new TransitionListener(entry, transition); } -function getAnimationListener(): android.view.animation.Animation.AnimationListener { +function getAnimationListener(): android.animation.Animator.AnimatorListener { if (!AnimationListener) { - @Interfaces([android.view.animation.Animation.AnimationListener]) - class AnimationListenerImpl extends java.lang.Object implements android.view.animation.Animation.AnimationListener { + @Interfaces([android.animation.Animator.AnimatorListener]) + class AnimationListenerImpl extends java.lang.Object implements android.animation.Animator.AnimatorListener { constructor() { super(); return global.__native(this); } - onAnimationStart(animation: ExpandedAnimation): void { - const entry = animation.entry; + onAnimationStart(animator: ExpandedAnimator): void { + const entry = animator.entry; addToWaitingQueue(entry); if (traceEnabled()) { - traceWrite(`START ${animation.transitionType} for ${entry.fragmentTag}`, traceCategories.Transition); + traceWrite(`START ${animator.transitionType} for ${entry.fragmentTag}`, traceCategories.Transition); } } - onAnimationRepeat(animation: ExpandedAnimation): void { + onAnimationRepeat(animator: ExpandedAnimator): void { if (traceEnabled()) { - traceWrite(`REPEAT ${animation.transitionType} for ${animation.entry.fragmentTag}`, traceCategories.Transition); + traceWrite(`REPEAT ${animator.transitionType} for ${animator.entry.fragmentTag}`, traceCategories.Transition); } } - onAnimationEnd(animation: ExpandedAnimation): void { + onAnimationEnd(animator: ExpandedAnimator): void { if (traceEnabled()) { - traceWrite(`END ${animation.transitionType} for ${animation.entry.fragmentTag}`, traceCategories.Transition); + traceWrite(`END ${animator.transitionType} for ${animator.entry.fragmentTag}`, traceCategories.Transition); } - transitionOrAnimationCompleted(animation.entry); + transitionOrAnimationCompleted(animator.entry); } - onAnimationCancel(animation: ExpandedAnimation): void { + onAnimationCancel(animator: ExpandedAnimator): void { if (traceEnabled()) { - traceWrite(`CANCEL ${animation.transitionType} for ${animation.entry.fragmentTag}`, traceCategories.Transition); + traceWrite(`CANCEL ${animator.transitionType} for ${animator.entry.fragmentTag}`, traceCategories.Transition); } } } @@ -367,18 +368,19 @@ function addToWaitingQueue(entry: ExpandedEntry): void { entries.add(entry); } -function clearAnimationListener(animation: ExpandedAnimation): void { - if (!animation) { +function clearAnimationListener(animator: ExpandedAnimator, listener: android.animation.Animator.AnimatorListener): void { + if (!animator) { return; } + animator.removeListener(listener); + if (traceEnabled()) { - const entry = animation.entry; - traceWrite(`Clear ${animation.transitionType} - ${entry.transition} for ${entry.fragmentTag}`, traceCategories.Transition); + const entry = animator.entry; + traceWrite(`Clear ${animator.transitionType} - ${entry.transition} for ${entry.fragmentTag}`, traceCategories.Transition); } - animation.setAnimationListener(null); - animation.entry = null; + animator.entry = null; } function clearExitAndReenterTransitions(entry: ExpandedEntry, removeListener: boolean): void { @@ -477,10 +479,11 @@ function clearEntry(entry: ExpandedEntry, removeListener: boolean): void { } if (removeListener) { - clearAnimationListener(entry.enterAnimation); - clearAnimationListener(entry.exitAnimation); - clearAnimationListener(entry.popEnterAnimation); - clearAnimationListener(entry.popExitAnimation); + const listener = getAnimationListener(); + clearAnimationListener(entry.enterAnimator, listener); + clearAnimationListener(entry.exitAnimator, listener); + clearAnimationListener(entry.popEnterAnimator, listener); + clearAnimationListener(entry.popExitAnimator, listener); } } @@ -617,21 +620,21 @@ function setupNewFragmentExplodeTransition(navTransition: NavigationTransition, function setupExitAndPopEnterAnimation(entry: ExpandedEntry, transition: Transition): void { const listener = getAnimationListener(); - // remove previous listener if we are changing the animation. - clearAnimationListener(entry.exitAnimation); - clearAnimationListener(entry.popEnterAnimation); + // remove previous listener if we are changing the animator. + clearAnimationListener(entry.exitAnimator, listener); + clearAnimationListener(entry.popEnterAnimator, listener); - const exitAnimation = transition.createAndroidAnimation(AndroidTransitionType.exit); - exitAnimation.transitionType = AndroidTransitionType.exit; - exitAnimation.entry = entry; - exitAnimation.setAnimationListener(listener); - entry.exitAnimation = exitAnimation; + const exitAnimator = transition.createAndroidAnimator(AndroidTransitionType.exit); + exitAnimator.transitionType = AndroidTransitionType.exit; + exitAnimator.entry = entry; + exitAnimator.addListener(listener); + entry.exitAnimator = exitAnimator; - const popEnterAnimation = transition.createAndroidAnimation(AndroidTransitionType.popEnter); - popEnterAnimation.transitionType = AndroidTransitionType.popEnter; - popEnterAnimation.entry = entry; - popEnterAnimation.setAnimationListener(listener); - entry.popEnterAnimation = popEnterAnimation; + const popEnterAnimator = transition.createAndroidAnimator(AndroidTransitionType.popEnter); + popEnterAnimator.transitionType = AndroidTransitionType.popEnter; + popEnterAnimator.entry = entry; + popEnterAnimator.addListener(listener); + entry.popEnterAnimator = popEnterAnimator; } function setupAllAnimation(entry: ExpandedEntry, transition: Transition): void { @@ -640,33 +643,33 @@ function setupAllAnimation(entry: ExpandedEntry, transition: Transition): void { // setupAllAnimation is called only for new fragments so we don't // need to clearAnimationListener for enter & popExit animators. - const enterAnimation = transition.createAndroidAnimation(AndroidTransitionType.enter); - enterAnimation.transitionType = AndroidTransitionType.enter; - enterAnimation.entry = entry; - enterAnimation.setAnimationListener(listener); - entry.enterAnimation = enterAnimation; + const enterAnimator = transition.createAndroidAnimator(AndroidTransitionType.enter); + enterAnimator.transitionType = AndroidTransitionType.enter; + enterAnimator.entry = entry; + enterAnimator.addListener(listener); + entry.enterAnimator = enterAnimator; - const popExitAnimation = transition.createAndroidAnimation(AndroidTransitionType.popExit); - popExitAnimation.transitionType = AndroidTransitionType.popExit; - popExitAnimation.entry = entry; - popExitAnimation.setAnimationListener(listener); - entry.popExitAnimation = popExitAnimation; + const popExitAnimator = transition.createAndroidAnimator(AndroidTransitionType.popExit); + popExitAnimator.transitionType = AndroidTransitionType.popExit; + popExitAnimator.entry = entry; + popExitAnimator.addListener(listener); + entry.popExitAnimator = popExitAnimator; } function setupDefaultAnimations(entry: ExpandedEntry, transition: Transition): void { const listener = getAnimationListener(); - const enterAnimation = transition.createAndroidAnimation(AndroidTransitionType.enter); - enterAnimation.transitionType = AndroidTransitionType.enter; - enterAnimation.entry = entry; - enterAnimation.setAnimationListener(listener); - entry.defaultEnterAnimation = enterAnimation; + const enterAnimator = transition.createAndroidAnimator(AndroidTransitionType.enter); + enterAnimator.transitionType = AndroidTransitionType.enter; + enterAnimator.entry = entry; + enterAnimator.addListener(listener); + entry.defaultEnterAnimator = enterAnimator; - const exitAnimation = transition.createAndroidAnimation(AndroidTransitionType.exit); - exitAnimation.transitionType = AndroidTransitionType.exit; - exitAnimation.entry = entry; - exitAnimation.setAnimationListener(listener); - entry.defaultExitAnimation = exitAnimation; + const exitAnimator = transition.createAndroidAnimator(AndroidTransitionType.exit); + exitAnimator.transitionType = AndroidTransitionType.exit; + exitAnimator.entry = entry; + exitAnimator.addListener(listener); + entry.defaultExitAnimator = exitAnimator; } function setUpNativeTransition(navigationTransition: NavigationTransition, nativeTransition: android.transition.Transition) { @@ -729,10 +732,10 @@ function printTransitions(entry: ExpandedEntry) { } if (entry.transition) { - result += `enterAnimator=${entry.enterAnimation}, `; - result += `exitAnimator=${entry.exitAnimation}, `; - result += `popEnterAnimator=${entry.popEnterAnimation}, `; - result += `popExitAnimator=${entry.popExitAnimation}, `; + result += `enterAnimator=${entry.enterAnimator}, `; + result += `exitAnimator=${entry.exitAnimator}, `; + result += `popEnterAnimator=${entry.popEnterAnimator}, `; + result += `popExitAnimator=${entry.popExitAnimator}, `; } if (sdkVersion() >= 21) { const fragment = entry.fragment; @@ -745,16 +748,20 @@ function printTransitions(entry: ExpandedEntry) { } } -class NoTransition extends Transition { - public createAndroidAnimation(transitionType: string): android.view.animation.Animation { - const animation = new android.view.animation.AlphaAnimation(1, 1); - // NOTE: this should not be necessary when we revert to Animators API - // HACK: Android view animation with zero duration seems to be buggy and raises animation listener events in illogical (wrong?) order: - // "enter" start -> "enter" end -> "exit" start -> "exit" end; - // we would expect events to overlap "exit" start -> "enter" start -> "exit" end -> "enter" end, or at least - // "exit" start / end to be raised before "enter" start / end - animation.setDuration(1); +function javaObjectArray(...params: java.lang.Object[]) { + const nativeArray = Array.create(java.lang.Object, params.length); + params.forEach((value, i) => nativeArray[i] = value); + return nativeArray; +} - return animation; +function createDummyZeroDurationAnimator(): android.animation.Animator { + const animator = android.animation.ValueAnimator.ofObject(intEvaluator(), javaObjectArray(java.lang.Integer.valueOf(0), java.lang.Integer.valueOf(1))); + animator.setDuration(0); + return animator; +} + +class NoTransition extends Transition { + public createAndroidAnimator(transitionType: string): android.animation.Animator { + return createDummyZeroDurationAnimator(); } } diff --git a/tns-core-modules/ui/frame/fragment.transitions.d.ts b/tns-core-modules/ui/frame/fragment.transitions.d.ts index bf864da7c..31500489c 100644 --- a/tns-core-modules/ui/frame/fragment.transitions.d.ts +++ b/tns-core-modules/ui/frame/fragment.transitions.d.ts @@ -28,7 +28,7 @@ export function _setAndroidFragmentTransitions( /** * @private */ -export function _onFragmentCreateAnimation(entry: BackstackEntry, fragment: any, nextAnim: number, enter: boolean): any; +export function _onFragmentCreateAnimator(entry: BackstackEntry, fragment: any, nextAnim: number, enter: boolean): any; /** * @private */ diff --git a/tns-core-modules/ui/frame/frame.android.ts b/tns-core-modules/ui/frame/frame.android.ts index fad8bf09e..6dba886d6 100644 --- a/tns-core-modules/ui/frame/frame.android.ts +++ b/tns-core-modules/ui/frame/frame.android.ts @@ -13,7 +13,7 @@ import { } from "./frame-common"; import { - _setAndroidFragmentTransitions, _onFragmentCreateAnimation, _getAnimatedEntries, + _setAndroidFragmentTransitions, _onFragmentCreateAnimator, _getAnimatedEntries, _updateTransitions, _reverseTransitions, _clearEntry, _clearFragment, AnimationType } from "./fragment.transitions"; @@ -667,7 +667,7 @@ class FragmentCallbacksImplementation implements AndroidFragmentCallbacks { } @profile - public onCreateAnimation(fragment: android.support.v4.app.Fragment, transit: number, enter: boolean, nextAnim: number, superFunc: Function): android.view.animation.Animation { + public onCreateAnimator(fragment: android.support.v4.app.Fragment, transit: number, enter: boolean, nextAnim: number, superFunc: Function): android.animation.Animator { let nextAnimString: string; switch (nextAnim) { case AnimationType.enterFakeResourceId: nextAnimString = "enter"; break; @@ -676,16 +676,16 @@ class FragmentCallbacksImplementation implements AndroidFragmentCallbacks { case AnimationType.popExitFakeResourceId: nextAnimString = "popExit"; break; } - let animation = _onFragmentCreateAnimation(this.entry, fragment, nextAnim, enter); - if (!animation) { - animation = superFunc.call(fragment, transit, enter, nextAnim); + let animator = _onFragmentCreateAnimator(this.entry, fragment, nextAnim, enter); + if (!animator) { + animator = superFunc.call(fragment, transit, enter, nextAnim); } if (traceEnabled()) { - traceWrite(`${fragment}.onCreateAnimation(${transit}, ${enter ? "enter" : "exit"}, ${nextAnimString}): ${animation ? "animation" : "no animation"}`, traceCategories.NativeLifecycle); + traceWrite(`${fragment}.onCreateAnimator(${transit}, ${enter ? "enter" : "exit"}, ${nextAnimString}): ${animator ? "animator" : "no animator"}`, traceCategories.NativeLifecycle); } - return animation; + return animator; } @profile diff --git a/tns-core-modules/ui/frame/frame.d.ts b/tns-core-modules/ui/frame/frame.d.ts index 38638d553..6a84735e7 100644 --- a/tns-core-modules/ui/frame/frame.d.ts +++ b/tns-core-modules/ui/frame/frame.d.ts @@ -414,7 +414,7 @@ export interface AndroidActivityCallbacks { export interface AndroidFragmentCallbacks { onHiddenChanged(fragment: any, hidden: boolean, superFunc: Function): void; - onCreateAnimation(fragment: any, transit: number, enter: boolean, nextAnim: number, superFunc: Function): any; + onCreateAnimator(fragment: any, transit: number, enter: boolean, nextAnim: number, superFunc: Function): any; onCreate(fragment: any, savedInstanceState: any, superFunc: Function): void; onCreateView(fragment: any, inflater: any, container: any, savedInstanceState: any, superFunc: Function): any; onSaveInstanceState(fragment: any, outState: any, superFunc: Function): void; diff --git a/tns-core-modules/ui/transition/fade-transition.android.ts b/tns-core-modules/ui/transition/fade-transition.android.ts index 244ae7f64..f96c035e0 100644 --- a/tns-core-modules/ui/transition/fade-transition.android.ts +++ b/tns-core-modules/ui/transition/fade-transition.android.ts @@ -1,29 +1,28 @@ import { Transition, AndroidTransitionType } from "./transition"; export class FadeTransition extends Transition { - public createAndroidAnimation(transitionType: string): android.view.animation.Animation { - const alphaValues = []; + public createAndroidAnimator(transitionType: string): android.animation.Animator { + const alphaValues = Array.create("float", 2); switch (transitionType) { case AndroidTransitionType.enter: case AndroidTransitionType.popEnter: - alphaValues[0] = 0.0; - alphaValues[1] = 1.0; + alphaValues[0] = 0; + alphaValues[1] = 1; break; case AndroidTransitionType.exit: case AndroidTransitionType.popExit: - alphaValues[0] = 1.0; - alphaValues[1] = 0.0; + alphaValues[0] = 1; + alphaValues[1] = 0; break; } - const animation = new android.view.animation.AlphaAnimation(alphaValues[0], alphaValues[1]); + const animator = android.animation.ObjectAnimator.ofFloat(null, "alpha", alphaValues); const duration = this.getDuration(); if (duration !== undefined) { - animation.setDuration(duration); + animator.setDuration(duration); } - animation.setInterpolator(this.getCurve()); - - return animation; + animator.setInterpolator(this.getCurve()); + return animator; } } diff --git a/tns-core-modules/ui/transition/flip-transition.android.ts b/tns-core-modules/ui/transition/flip-transition.android.ts index 6c5d989a7..612ab0117 100644 --- a/tns-core-modules/ui/transition/flip-transition.android.ts +++ b/tns-core-modules/ui/transition/flip-transition.android.ts @@ -1,6 +1,6 @@ import { Transition, AndroidTransitionType } from "./transition"; -// http://developer.android.com/training/animation/cardflip.html +//http://developer.android.com/training/animation/cardflip.html export class FlipTransition extends Transition { private _direction: string; @@ -9,117 +9,109 @@ export class FlipTransition extends Transition { this._direction = direction; } - public createAndroidAnimation(transitionType: string): android.view.animation.Animation { - ensureRotate3dAnimationClass(); - - let animation: android.view.animation.Animation; - let animationSet: android.view.animation.AnimationSet - let rotateAnimation: android.view.animation.Animation; - let alphaAnimation: android.view.animation.Animation; + public createAndroidAnimator(transitionType: string): android.animation.Animator { + let objectAnimators; + let values; + let animator: android.animation.ObjectAnimator; + const animatorSet = new android.animation.AnimatorSet(); const fullDuration = this.getDuration() || 300; const interpolator = this.getCurve(); const rotationY = this._direction === "right" ? 180 : -180; switch (transitionType) { case AndroidTransitionType.enter: // card_flip_right_in - animation = new Rotate3dAnimationClass(rotationY, 0.0, 0.5, 0.5); - animation.setInterpolator(interpolator); - animation.setDuration(fullDuration); + objectAnimators = Array.create(android.animation.Animator, 3); + + values = Array.create("float", 2); + values[0] = 1.0; + values[1] = 0.0; + animator = android.animation.ObjectAnimator.ofFloat(null, "alpha", values); + animator.setDuration(0); + objectAnimators[0] = animator; + + values = Array.create("float", 2); + values[0] = rotationY; + values[1] = 0.0; + animator = android.animation.ObjectAnimator.ofFloat(null, "rotationY", values); + animator.setInterpolator(interpolator); + animator.setDuration(fullDuration); + objectAnimators[1] = animator; + + values = Array.create("float", 2); + values[0] = 0.0; + values[1] = 1.0; + animator = android.animation.ObjectAnimator.ofFloat(null, "alpha", values); + animator.setStartDelay(fullDuration / 2); + animator.setDuration(1); + objectAnimators[2] = animator; break; case AndroidTransitionType.exit: // card_flip_right_out - animation = animationSet = new android.view.animation.AnimationSet(false /* shareInterpolator */); - - rotateAnimation = new Rotate3dAnimationClass(0.0, -rotationY, 0.5, 0.5); - rotateAnimation.setInterpolator(interpolator); - rotateAnimation.setDuration(fullDuration); - animationSet.addAnimation(rotateAnimation); + objectAnimators = Array.create(android.animation.Animator, 2); - alphaAnimation = new android.view.animation.AlphaAnimation(1.0, 0.0); - alphaAnimation.setStartOffset(fullDuration / 2); - alphaAnimation.setDuration(1); - animationSet.addAnimation(alphaAnimation); + values = Array.create("float", 2); + values[0] = 0.0; + values[1] = -rotationY; + animator = android.animation.ObjectAnimator.ofFloat(null, "rotationY", values); + animator.setInterpolator(interpolator); + animator.setDuration(fullDuration); + objectAnimators[0] = animator; + + values = Array.create("float", 2); + values[0] = 1.0; + values[1] = 0.0; + animator = android.animation.ObjectAnimator.ofFloat(null, "alpha", values); + animator.setStartDelay(fullDuration / 2); + animator.setDuration(1); + objectAnimators[1] = animator; break; case AndroidTransitionType.popEnter: // card_flip_left_in - animation = new Rotate3dAnimationClass(-rotationY, 0.0, 0.5, 0.5); - animation.setInterpolator(interpolator); - animation.setDuration(fullDuration); + objectAnimators = Array.create(android.animation.Animator, 3); + + values = Array.create("float", 2); + values[0] = 1.0; + values[1] = 0.0; + animator = android.animation.ObjectAnimator.ofFloat(null, "alpha", values); + animator.setDuration(0); + objectAnimators[0] = animator; + + values = Array.create("float", 2); + values[0] = -rotationY; + values[1] = 0.0; + animator = android.animation.ObjectAnimator.ofFloat(null, "rotationY", values); + animator.setInterpolator(interpolator); + animator.setDuration(fullDuration); + objectAnimators[1] = animator; + + values = Array.create("float", 2); + values[0] = 0.0; + values[1] = 1.0; + animator = android.animation.ObjectAnimator.ofFloat(null, "alpha", values); + animator.setStartDelay(fullDuration / 2); + animator.setDuration(1); + objectAnimators[2] = animator; break; case AndroidTransitionType.popExit: // card_flip_left_out - animation = animationSet = new android.view.animation.AnimationSet(false /* shareInterpolator */); - - rotateAnimation = new Rotate3dAnimationClass(0.0, rotationY, 0.5, 0.5); - rotateAnimation.setInterpolator(interpolator); - rotateAnimation.setDuration(fullDuration); - animationSet.addAnimation(rotateAnimation); + objectAnimators = Array.create(android.animation.Animator, 2); - alphaAnimation = new android.view.animation.AlphaAnimation(1.0, 0.0); - alphaAnimation.setStartOffset(fullDuration / 2); - alphaAnimation.setDuration(1); - animationSet.addAnimation(alphaAnimation); + values = Array.create("float", 2); + values[0] = 0.0; + values[1] = rotationY; + animator = android.animation.ObjectAnimator.ofFloat(null, "rotationY", values); + animator.setInterpolator(interpolator); + animator.setDuration(fullDuration); + objectAnimators[0] = animator; + + values = Array.create("float", 2); + values[0] = 1.0; + values[1] = 0.0; + animator = android.animation.ObjectAnimator.ofFloat(null, "alpha", values); + animator.setStartDelay(fullDuration / 2); + animator.setDuration(1); + objectAnimators[1] = animator; break; } - return animation; + animatorSet.playTogether(objectAnimators); + return animatorSet; } } - -let Rotate3dAnimationClass; -function ensureRotate3dAnimationClass() { - if (Rotate3dAnimationClass) { - return; - } - - /** - * Creates a new 3D rotation on the Y axis. The rotation is defined by its - * start angle and its end angle. Both angles are in degrees. The rotation - * is performed around a center point on the 2D space, definied by a pair - * of X and Y coordinates, called centerX and centerY. - * - * @param fromDegrees the start angle of the 3D rotation - * @param toDegrees the end angle of the 3D rotation - * @param centerX the X center of the 3D rotation (relative to self) - * @param centerY the Y center of the 3D rotation (relative to self) - */ - class Rotate3dAnimation extends android.view.animation.Animation { - private _camera: android.graphics.Camera; - private _pivotX: number; - private _pivotY: number; - - constructor( - private _fromDegrees: number, - private _toDegrees: number, - private _centerX: number, - private _centerY: number) { - super(); - return global.__native(this); - } - - public initialize(width: number, height: number, parentWidth: number, parentHeight: number) { - super.initialize(width, height, parentWidth, parentHeight); - this._pivotX = this.resolveSize(android.view.animation.Animation.RELATIVE_TO_SELF, this._centerX, width, parentWidth); - this._pivotY = this.resolveSize(android.view.animation.Animation.RELATIVE_TO_SELF, this._centerY, height, parentHeight); - this._camera = new android.graphics.Camera(); - } - - public applyTransformation(interpolatedTime: number, t: android.view.animation.Transformation) { - const fromDegrees = this._fromDegrees; - const degrees = fromDegrees + ((this._toDegrees - fromDegrees) * interpolatedTime); - - const pivotX = this._pivotX; - const pivotY = this._pivotY; - const camera = this._camera; - - const matrix: android.graphics.Matrix = t.getMatrix(); - - camera.save(); - camera.rotateY(degrees); - camera.getMatrix(matrix); - camera.restore(); - - matrix.preTranslate(-pivotX, -pivotY); - matrix.postTranslate(pivotX, pivotY); - } - } - - Rotate3dAnimationClass = Rotate3dAnimation; -} \ No newline at end of file diff --git a/tns-core-modules/ui/transition/slide-transition.android.ts b/tns-core-modules/ui/transition/slide-transition.android.ts index 3cb0c1365..eafe50362 100644 --- a/tns-core-modules/ui/transition/slide-transition.android.ts +++ b/tns-core-modules/ui/transition/slide-transition.android.ts @@ -13,8 +13,8 @@ export class SlideTransition extends transition.Transition { this._direction = direction; } - public createAndroidAnimation(transitionType: string): android.view.animation.Animation { - const translationValues = []; + public createAndroidAnimator(transitionType: string): android.animation.Animator { + const translationValues = Array.create("float", 2); switch (this._direction) { case "left": switch (transitionType) { @@ -98,22 +98,22 @@ export class SlideTransition extends transition.Transition { break; } - let animation; + let prop; + if (this._direction === "left" || this._direction === "right") { - animation = new android.view.animation.TranslateAnimation(translationValues[0], translationValues[1], 0, 0); + prop = "translationX"; } else { - animation = new android.view.animation.TranslateAnimation(0, 0, translationValues[0], translationValues[1]); + prop = "translationY"; } + const animator = android.animation.ObjectAnimator.ofFloat(null, prop, translationValues); const duration = this.getDuration(); if (duration !== undefined) { - animation.setDuration(duration); + animator.setDuration(duration); } - - animation.setInterpolator(this.getCurve()); - - return animation; + animator.setInterpolator(this.getCurve()); + return animator; } public toString(): string { diff --git a/tns-core-modules/ui/transition/transition.android.ts b/tns-core-modules/ui/transition/transition.android.ts index e9d9d6d36..95ddfa7a0 100644 --- a/tns-core-modules/ui/transition/transition.android.ts +++ b/tns-core-modules/ui/transition/transition.android.ts @@ -38,7 +38,7 @@ export class Transition implements TransitionDefinition { throw new Error("Abstract method call"); } - public createAndroidAnimation(transitionType: string): android.view.animation.Animation { + public createAndroidAnimator(transitionType: string): android.animation.Animator { throw new Error("Abstract method call"); } diff --git a/tns-core-modules/ui/transition/transition.d.ts b/tns-core-modules/ui/transition/transition.d.ts index f963b3c3e..ffbc94ba4 100644 --- a/tns-core-modules/ui/transition/transition.d.ts +++ b/tns-core-modules/ui/transition/transition.d.ts @@ -14,6 +14,6 @@ export class Transition { public getDuration(): number; public getCurve(): any; public animateIOSTransition(containerView: any, fromView: any, toView: any, operation: any, completion: (finished: boolean) => void): void; - public createAndroidAnimation(transitionType: string): any; + public createAndroidAnimator(transitionType: string): any; public toString(): string; } \ No newline at end of file diff --git a/tns-core-modules/ui/transition/transition.ios.ts b/tns-core-modules/ui/transition/transition.ios.ts index e6021999d..b146fd59f 100644 --- a/tns-core-modules/ui/transition/transition.ios.ts +++ b/tns-core-modules/ui/transition/transition.ios.ts @@ -24,7 +24,7 @@ export class Transition implements TransitionDefinition { throw new Error("Abstract method call"); } - public createAndroidAnimation(transitionType: string): any { + public createAndroidAnimator(transitionType: string): any { throw new Error("Abstract method call"); }