mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-11-05 13:26:48 +08:00
951 lines
24 KiB
TypeScript
951 lines
24 KiB
TypeScript
// Types.
|
|
import {
|
|
AnimationDefinitionInternal,
|
|
AnimationPromise,
|
|
PropertyAnimation,
|
|
} from "./animation-common";
|
|
import { View } from "../core/view";
|
|
|
|
// Requires
|
|
import {
|
|
AnimationBase,
|
|
Properties,
|
|
CubicBezierAnimationCurve,
|
|
} from "./animation-common";
|
|
import { Color } from "../../color";
|
|
import { Trace } from "../../trace";
|
|
import {
|
|
opacityProperty,
|
|
backgroundColorProperty,
|
|
rotateProperty,
|
|
rotateXProperty,
|
|
rotateYProperty,
|
|
translateXProperty,
|
|
translateYProperty,
|
|
scaleXProperty,
|
|
scaleYProperty,
|
|
heightProperty,
|
|
widthProperty,
|
|
PercentLength,
|
|
} from "../styling/style-properties";
|
|
import { layout } from "../../utils/utils";
|
|
import { device, screen } from "../../platform";
|
|
import lazy from "../../utils/lazy";
|
|
|
|
export * from "./animation-common";
|
|
|
|
let argbEvaluator: android.animation.ArgbEvaluator;
|
|
function ensureArgbEvaluator() {
|
|
if (!argbEvaluator) {
|
|
argbEvaluator = new android.animation.ArgbEvaluator();
|
|
}
|
|
}
|
|
|
|
let easeIn = lazy(() => new android.view.animation.AccelerateInterpolator(1));
|
|
let easeOut = lazy(() => new android.view.animation.DecelerateInterpolator(1));
|
|
let easeInOut = lazy(
|
|
() => new android.view.animation.AccelerateDecelerateInterpolator()
|
|
);
|
|
let linear = lazy(() => new android.view.animation.LinearInterpolator());
|
|
let bounce = lazy(() => new android.view.animation.BounceInterpolator());
|
|
|
|
let keyPrefix = "ui.animation.";
|
|
let propertyKeys = {};
|
|
propertyKeys[Properties.backgroundColor] = Symbol(
|
|
keyPrefix + Properties.backgroundColor
|
|
);
|
|
propertyKeys[Properties.opacity] = Symbol(keyPrefix + Properties.opacity);
|
|
propertyKeys[Properties.rotate] = Symbol(keyPrefix + Properties.rotate);
|
|
propertyKeys[Properties.scale] = Symbol(keyPrefix + Properties.scale);
|
|
propertyKeys[Properties.translate] = Symbol(keyPrefix + Properties.translate);
|
|
propertyKeys[Properties.height] = Symbol(keyPrefix + Properties.height);
|
|
propertyKeys[Properties.width] = Symbol(keyPrefix + Properties.width);
|
|
|
|
export function _resolveAnimationCurve(
|
|
curve:
|
|
| string
|
|
| CubicBezierAnimationCurve
|
|
| android.view.animation.Interpolator
|
|
| android.view.animation.LinearInterpolator
|
|
): android.view.animation.Interpolator {
|
|
switch (curve) {
|
|
case "easeIn":
|
|
if (Trace.isEnabled()) {
|
|
Trace.write(
|
|
"Animation curve resolved to android.view.animation.AccelerateInterpolator(1).",
|
|
Trace.categories.Animation
|
|
);
|
|
}
|
|
|
|
return easeIn();
|
|
case "easeOut":
|
|
if (Trace.isEnabled()) {
|
|
Trace.write(
|
|
"Animation curve resolved to android.view.animation.DecelerateInterpolator(1).",
|
|
Trace.categories.Animation
|
|
);
|
|
}
|
|
|
|
return easeOut();
|
|
case "easeInOut":
|
|
if (Trace.isEnabled()) {
|
|
Trace.write(
|
|
"Animation curve resolved to android.view.animation.AccelerateDecelerateInterpolator().",
|
|
Trace.categories.Animation
|
|
);
|
|
}
|
|
|
|
return easeInOut();
|
|
case "linear":
|
|
if (Trace.isEnabled()) {
|
|
Trace.write(
|
|
"Animation curve resolved to android.view.animation.LinearInterpolator().",
|
|
Trace.categories.Animation
|
|
);
|
|
}
|
|
|
|
return linear();
|
|
case "spring":
|
|
if (Trace.isEnabled()) {
|
|
Trace.write(
|
|
"Animation curve resolved to android.view.animation.BounceInterpolator().",
|
|
Trace.categories.Animation
|
|
);
|
|
}
|
|
|
|
return bounce();
|
|
case "ease":
|
|
return (<any>(
|
|
androidx
|
|
)).core.view.animation.PathInterpolatorCompat.create(
|
|
0.25,
|
|
0.1,
|
|
0.25,
|
|
1.0
|
|
);
|
|
default:
|
|
if (Trace.isEnabled()) {
|
|
Trace.write(
|
|
"Animation curve resolved to original: " + curve,
|
|
Trace.categories.Animation
|
|
);
|
|
}
|
|
if (curve instanceof CubicBezierAnimationCurve) {
|
|
return (<any>(
|
|
androidx
|
|
)).core.view.animation.PathInterpolatorCompat.create(
|
|
curve.x1,
|
|
curve.y1,
|
|
curve.x2,
|
|
curve.y2
|
|
);
|
|
} else if (curve && (<any>curve).getInterpolation) {
|
|
return <android.view.animation.Interpolator>curve;
|
|
} else if (
|
|
<any>curve instanceof android.view.animation.LinearInterpolator
|
|
) {
|
|
return <android.view.animation.Interpolator>curve;
|
|
} else {
|
|
throw new Error(`Invalid animation curve: ${curve}`);
|
|
}
|
|
}
|
|
}
|
|
|
|
function getAndroidRepeatCount(iterations: number): number {
|
|
return iterations === Number.POSITIVE_INFINITY
|
|
? android.view.animation.Animation.INFINITE
|
|
: iterations - 1;
|
|
}
|
|
|
|
function createObjectAnimator(
|
|
nativeView: android.view.View,
|
|
propertyName: string,
|
|
value: number
|
|
): android.animation.ObjectAnimator {
|
|
let arr = Array.create("float", 1);
|
|
arr[0] = value;
|
|
|
|
return android.animation.ObjectAnimator.ofFloat(
|
|
nativeView,
|
|
propertyName,
|
|
arr
|
|
);
|
|
}
|
|
|
|
function createAnimationSet(
|
|
animators: android.animation.ObjectAnimator[],
|
|
iterations: number
|
|
): android.animation.AnimatorSet {
|
|
iterations = getAndroidRepeatCount(iterations);
|
|
|
|
const animatorSet = new android.animation.AnimatorSet();
|
|
const animatorsArray = Array.create(
|
|
android.animation.Animator,
|
|
animators.length
|
|
);
|
|
|
|
animators.forEach((animator, index) => {
|
|
animatorsArray[index] = animator;
|
|
|
|
//TODO: not sure if we have to do that for each animator
|
|
animatorsArray[index].setRepeatCount(iterations);
|
|
});
|
|
|
|
animatorSet.playTogether(animatorsArray);
|
|
animatorSet.setupStartValues();
|
|
|
|
return animatorSet;
|
|
}
|
|
|
|
export class Animation extends AnimationBase {
|
|
private _animatorListener: android.animation.Animator.AnimatorListener;
|
|
private _nativeAnimatorsArray: any;
|
|
private _animatorSet: android.animation.AnimatorSet;
|
|
private _animators: Array<android.animation.Animator>;
|
|
private _propertyUpdateCallbacks: Array<Function>;
|
|
private _propertyResetCallbacks: Array<Function>;
|
|
private _valueSource: "animation" | "keyframe";
|
|
private _target: View;
|
|
private _resetOnFinish: boolean = true;
|
|
|
|
constructor(
|
|
animationDefinitions: Array<AnimationDefinitionInternal>,
|
|
playSequentially?: boolean
|
|
) {
|
|
super(animationDefinitions, playSequentially);
|
|
|
|
this._valueSource = "animation";
|
|
if (
|
|
animationDefinitions.length > 0 &&
|
|
animationDefinitions[0].valueSource !== undefined
|
|
) {
|
|
this._valueSource = animationDefinitions[0].valueSource;
|
|
}
|
|
|
|
let that = new WeakRef(this);
|
|
this._animatorListener = new android.animation.Animator.AnimatorListener(
|
|
{
|
|
onAnimationStart: function (
|
|
animator: android.animation.Animator
|
|
): void {
|
|
if (Trace.isEnabled()) {
|
|
Trace.write(
|
|
"MainAnimatorListener.onAndroidAnimationStart(" +
|
|
animator +
|
|
")",
|
|
Trace.categories.Animation
|
|
);
|
|
}
|
|
},
|
|
onAnimationRepeat: function (
|
|
animator: android.animation.Animator
|
|
): void {
|
|
if (Trace.isEnabled()) {
|
|
Trace.write(
|
|
"MainAnimatorListener.onAnimationRepeat(" +
|
|
animator +
|
|
")",
|
|
Trace.categories.Animation
|
|
);
|
|
}
|
|
},
|
|
onAnimationEnd: function (
|
|
animator: android.animation.Animator
|
|
): void {
|
|
if (Trace.isEnabled()) {
|
|
Trace.write(
|
|
"MainAnimatorListener.onAnimationEnd(" +
|
|
animator +
|
|
")",
|
|
Trace.categories.Animation
|
|
);
|
|
}
|
|
const thisRef = that.get();
|
|
if (thisRef) {
|
|
thisRef._onAndroidAnimationEnd();
|
|
}
|
|
},
|
|
onAnimationCancel: function (
|
|
animator: android.animation.Animator
|
|
): void {
|
|
if (Trace.isEnabled()) {
|
|
Trace.write(
|
|
"MainAnimatorListener.onAnimationCancel(" +
|
|
animator +
|
|
")",
|
|
Trace.categories.Animation
|
|
);
|
|
}
|
|
const thisRef = that.get();
|
|
if (thisRef) {
|
|
thisRef._onAndroidAnimationCancel();
|
|
}
|
|
},
|
|
}
|
|
);
|
|
}
|
|
|
|
public play(resetOnFinish?: boolean): AnimationPromise {
|
|
if (resetOnFinish !== undefined) {
|
|
this._resetOnFinish = resetOnFinish;
|
|
}
|
|
|
|
if (this.isPlaying) {
|
|
return this._rejectAlreadyPlaying();
|
|
}
|
|
|
|
if (this._animatorSet) {
|
|
return this._play();
|
|
}
|
|
|
|
this._animators = new Array<android.animation.Animator>();
|
|
this._propertyUpdateCallbacks = new Array<Function>();
|
|
this._propertyResetCallbacks = new Array<Function>();
|
|
|
|
for (
|
|
let i = 0, length = this._propertyAnimations.length;
|
|
i < length;
|
|
i++
|
|
) {
|
|
this._createAnimators(this._propertyAnimations[i]);
|
|
}
|
|
|
|
this._nativeAnimatorsArray = Array.create(
|
|
android.animation.Animator,
|
|
this._animators.length
|
|
);
|
|
for (let i = 0, length = this._animators.length; i < length; i++) {
|
|
this._nativeAnimatorsArray[i] = this._animators[i];
|
|
}
|
|
|
|
this._animatorSet = new android.animation.AnimatorSet();
|
|
this._animatorSet.addListener(this._animatorListener);
|
|
|
|
return this._play();
|
|
}
|
|
|
|
public cancel(): void {
|
|
if (!this.isPlaying) {
|
|
Trace.write(
|
|
"Animation is not currently playing.",
|
|
Trace.categories.Animation,
|
|
Trace.messageType.warn
|
|
);
|
|
|
|
return;
|
|
}
|
|
|
|
Trace.write("Cancelling AnimatorSet.", Trace.categories.Animation);
|
|
|
|
this._animatorSet.cancel();
|
|
}
|
|
|
|
public _resolveAnimationCurve(
|
|
curve:
|
|
| string
|
|
| CubicBezierAnimationCurve
|
|
| android.view.animation.Interpolator
|
|
): android.view.animation.Interpolator {
|
|
return _resolveAnimationCurve(curve);
|
|
}
|
|
|
|
private _play(): AnimationPromise {
|
|
const animationFinishedPromise = super.play();
|
|
|
|
if (device.sdkVersion <= "23") {
|
|
this._animatorSet = new android.animation.AnimatorSet();
|
|
this._animatorSet.addListener(this._animatorListener);
|
|
}
|
|
|
|
if (this._animators.length > 0) {
|
|
if (this._playSequentially) {
|
|
this._animatorSet.playSequentially(this._nativeAnimatorsArray);
|
|
} else {
|
|
this._animatorSet.playTogether(this._nativeAnimatorsArray);
|
|
}
|
|
}
|
|
|
|
if (Trace.isEnabled()) {
|
|
Trace.write(
|
|
"Starting " +
|
|
this._nativeAnimatorsArray.length +
|
|
" animations " +
|
|
(this._playSequentially ? "sequentially." : "together."),
|
|
Trace.categories.Animation
|
|
);
|
|
}
|
|
|
|
this._animatorSet.setupStartValues();
|
|
this._animatorSet.start();
|
|
|
|
return animationFinishedPromise;
|
|
}
|
|
|
|
private _onAndroidAnimationEnd() {
|
|
// tslint:disable-line
|
|
if (!this.isPlaying) {
|
|
// It has been cancelled
|
|
return;
|
|
}
|
|
|
|
this._propertyUpdateCallbacks.forEach((v) => v());
|
|
this._resolveAnimationFinishedPromise();
|
|
|
|
if (this._resetOnFinish && this._target) {
|
|
this._target._removeAnimation(this);
|
|
}
|
|
}
|
|
|
|
private _onAndroidAnimationCancel() {
|
|
// tslint:disable-line
|
|
this._propertyResetCallbacks.forEach((v) => v());
|
|
this._rejectAnimationFinishedPromise();
|
|
|
|
if (this._target) {
|
|
this._target._removeAnimation(this);
|
|
}
|
|
}
|
|
|
|
private _createAnimators(propertyAnimation: PropertyAnimation): void {
|
|
if (!propertyAnimation.target.nativeViewProtected) {
|
|
return;
|
|
}
|
|
|
|
if (Trace.isEnabled()) {
|
|
Trace.write(
|
|
"Creating ObjectAnimator(s) for animation: " +
|
|
Animation._getAnimationInfo(propertyAnimation) +
|
|
"...",
|
|
Trace.categories.Animation
|
|
);
|
|
}
|
|
|
|
if (
|
|
propertyAnimation.target === null ||
|
|
propertyAnimation.target === undefined
|
|
) {
|
|
throw new Error(
|
|
`Animation target cannot be null or undefined; property: ${propertyAnimation.property}; value: ${propertyAnimation.value};`
|
|
);
|
|
}
|
|
|
|
if (
|
|
propertyAnimation.property === null ||
|
|
propertyAnimation.property === undefined
|
|
) {
|
|
throw new Error(
|
|
`Animation property cannot be null or undefined; target: ${propertyAnimation.target}; value: ${propertyAnimation.value};`
|
|
);
|
|
}
|
|
|
|
if (
|
|
propertyAnimation.value === null ||
|
|
propertyAnimation.value === undefined
|
|
) {
|
|
throw new Error(
|
|
`Animation value cannot be null or undefined; target: ${propertyAnimation.target}; property: ${propertyAnimation.property};`
|
|
);
|
|
}
|
|
|
|
this._target = propertyAnimation.target;
|
|
|
|
const nativeView = <android.view.View>(
|
|
propertyAnimation.target.nativeViewProtected
|
|
);
|
|
const animators = new Array<android.animation.Animator>();
|
|
const propertyUpdateCallbacks = new Array<Function>();
|
|
const propertyResetCallbacks = new Array<Function>();
|
|
let originalValue1;
|
|
let originalValue2;
|
|
let originalValue3;
|
|
const density = layout.getDisplayDensity();
|
|
|
|
let key = propertyKeys[propertyAnimation.property];
|
|
if (key) {
|
|
propertyAnimation.target[key] = propertyAnimation;
|
|
}
|
|
function checkAnimation(cb) {
|
|
return () => {
|
|
if (propertyAnimation.target[key] === propertyAnimation) {
|
|
delete propertyAnimation.target[key];
|
|
cb();
|
|
}
|
|
};
|
|
}
|
|
|
|
let setLocal = this._valueSource === "animation";
|
|
const style = propertyAnimation.target.style;
|
|
switch (propertyAnimation.property) {
|
|
case Properties.opacity:
|
|
opacityProperty._initDefaultNativeValue(style);
|
|
|
|
originalValue1 = nativeView.getAlpha();
|
|
propertyUpdateCallbacks.push(
|
|
checkAnimation(() => {
|
|
propertyAnimation.target.style[
|
|
setLocal
|
|
? opacityProperty.name
|
|
: opacityProperty.keyframe
|
|
] = propertyAnimation.value;
|
|
})
|
|
);
|
|
propertyResetCallbacks.push(
|
|
checkAnimation(() => {
|
|
if (setLocal) {
|
|
propertyAnimation.target.style[
|
|
opacityProperty.name
|
|
] = originalValue1;
|
|
} else {
|
|
propertyAnimation.target.style[
|
|
opacityProperty.keyframe
|
|
] = originalValue1;
|
|
}
|
|
if (propertyAnimation.target.nativeViewProtected) {
|
|
propertyAnimation.target[opacityProperty.setNative](
|
|
propertyAnimation.target.style.opacity
|
|
);
|
|
}
|
|
})
|
|
);
|
|
animators.push(
|
|
createObjectAnimator(
|
|
nativeView,
|
|
"alpha",
|
|
propertyAnimation.value
|
|
)
|
|
);
|
|
break;
|
|
|
|
case Properties.backgroundColor:
|
|
backgroundColorProperty._initDefaultNativeValue(style);
|
|
|
|
ensureArgbEvaluator();
|
|
originalValue1 = propertyAnimation.target.backgroundColor;
|
|
const nativeArray = Array.create(java.lang.Object, 2);
|
|
nativeArray[0] = propertyAnimation.target.backgroundColor
|
|
? java.lang.Integer.valueOf(
|
|
(<Color>propertyAnimation.target.backgroundColor)
|
|
.argb
|
|
)
|
|
: java.lang.Integer.valueOf(-1);
|
|
nativeArray[1] = java.lang.Integer.valueOf(
|
|
(<Color>propertyAnimation.value).argb
|
|
);
|
|
let animator = android.animation.ValueAnimator.ofObject(
|
|
argbEvaluator,
|
|
nativeArray
|
|
);
|
|
animator.addUpdateListener(
|
|
new android.animation.ValueAnimator.AnimatorUpdateListener({
|
|
onAnimationUpdate(
|
|
animator: android.animation.ValueAnimator
|
|
) {
|
|
let argb = (<java.lang.Integer>(
|
|
animator.getAnimatedValue()
|
|
)).intValue();
|
|
propertyAnimation.target.style[
|
|
setLocal
|
|
? backgroundColorProperty.name
|
|
: backgroundColorProperty.keyframe
|
|
] = new Color(argb);
|
|
},
|
|
})
|
|
);
|
|
|
|
propertyUpdateCallbacks.push(
|
|
checkAnimation(() => {
|
|
propertyAnimation.target.style[
|
|
setLocal
|
|
? backgroundColorProperty.name
|
|
: backgroundColorProperty.keyframe
|
|
] = propertyAnimation.value;
|
|
})
|
|
);
|
|
propertyResetCallbacks.push(
|
|
checkAnimation(() => {
|
|
if (setLocal) {
|
|
propertyAnimation.target.style[
|
|
backgroundColorProperty.name
|
|
] = originalValue1;
|
|
} else {
|
|
propertyAnimation.target.style[
|
|
backgroundColorProperty.keyframe
|
|
] = originalValue1;
|
|
}
|
|
|
|
if (
|
|
propertyAnimation.target.nativeViewProtected &&
|
|
propertyAnimation.target[
|
|
backgroundColorProperty.setNative
|
|
]
|
|
) {
|
|
propertyAnimation.target[
|
|
backgroundColorProperty.setNative
|
|
](propertyAnimation.target.style.backgroundColor);
|
|
}
|
|
})
|
|
);
|
|
animators.push(animator);
|
|
break;
|
|
|
|
case Properties.translate:
|
|
translateXProperty._initDefaultNativeValue(style);
|
|
translateYProperty._initDefaultNativeValue(style);
|
|
|
|
originalValue1 = nativeView.getTranslationX() / density;
|
|
originalValue2 = nativeView.getTranslationY() / density;
|
|
|
|
propertyUpdateCallbacks.push(
|
|
checkAnimation(() => {
|
|
propertyAnimation.target.style[
|
|
setLocal
|
|
? translateXProperty.name
|
|
: translateXProperty.keyframe
|
|
] = propertyAnimation.value.x;
|
|
propertyAnimation.target.style[
|
|
setLocal
|
|
? translateYProperty.name
|
|
: translateYProperty.keyframe
|
|
] = propertyAnimation.value.y;
|
|
})
|
|
);
|
|
|
|
propertyResetCallbacks.push(
|
|
checkAnimation(() => {
|
|
if (setLocal) {
|
|
propertyAnimation.target.style[
|
|
translateXProperty.name
|
|
] = originalValue1;
|
|
propertyAnimation.target.style[
|
|
translateYProperty.name
|
|
] = originalValue2;
|
|
} else {
|
|
propertyAnimation.target.style[
|
|
translateXProperty.keyframe
|
|
] = originalValue1;
|
|
propertyAnimation.target.style[
|
|
translateYProperty.keyframe
|
|
] = originalValue2;
|
|
}
|
|
|
|
if (propertyAnimation.target.nativeViewProtected) {
|
|
propertyAnimation.target[
|
|
translateXProperty.setNative
|
|
](propertyAnimation.target.style.translateX);
|
|
propertyAnimation.target[
|
|
translateYProperty.setNative
|
|
](propertyAnimation.target.style.translateY);
|
|
}
|
|
})
|
|
);
|
|
|
|
animators.push(
|
|
createAnimationSet(
|
|
[
|
|
createObjectAnimator(
|
|
nativeView,
|
|
"translationX",
|
|
propertyAnimation.value.x * density
|
|
),
|
|
createObjectAnimator(
|
|
nativeView,
|
|
"translationY",
|
|
propertyAnimation.value.y * density
|
|
),
|
|
],
|
|
propertyAnimation.iterations
|
|
)
|
|
);
|
|
break;
|
|
|
|
case Properties.scale:
|
|
scaleXProperty._initDefaultNativeValue(style);
|
|
scaleYProperty._initDefaultNativeValue(style);
|
|
|
|
originalValue1 = nativeView.getScaleX();
|
|
originalValue2 = nativeView.getScaleY();
|
|
|
|
propertyUpdateCallbacks.push(
|
|
checkAnimation(() => {
|
|
propertyAnimation.target.style[
|
|
setLocal
|
|
? scaleXProperty.name
|
|
: scaleXProperty.keyframe
|
|
] = propertyAnimation.value.x;
|
|
propertyAnimation.target.style[
|
|
setLocal
|
|
? scaleYProperty.name
|
|
: scaleYProperty.keyframe
|
|
] = propertyAnimation.value.y;
|
|
})
|
|
);
|
|
|
|
propertyResetCallbacks.push(
|
|
checkAnimation(() => {
|
|
if (setLocal) {
|
|
propertyAnimation.target.style[
|
|
scaleXProperty.name
|
|
] = originalValue1;
|
|
propertyAnimation.target.style[
|
|
scaleYProperty.name
|
|
] = originalValue2;
|
|
} else {
|
|
propertyAnimation.target.style[
|
|
scaleXProperty.keyframe
|
|
] = originalValue1;
|
|
propertyAnimation.target.style[
|
|
scaleYProperty.keyframe
|
|
] = originalValue2;
|
|
}
|
|
|
|
if (propertyAnimation.target.nativeViewProtected) {
|
|
propertyAnimation.target[scaleXProperty.setNative](
|
|
propertyAnimation.target.style.scaleX
|
|
);
|
|
propertyAnimation.target[scaleYProperty.setNative](
|
|
propertyAnimation.target.style.scaleY
|
|
);
|
|
}
|
|
})
|
|
);
|
|
|
|
animators.push(
|
|
createAnimationSet(
|
|
[
|
|
createObjectAnimator(
|
|
nativeView,
|
|
"scaleX",
|
|
propertyAnimation.value.x
|
|
),
|
|
createObjectAnimator(
|
|
nativeView,
|
|
"scaleY",
|
|
propertyAnimation.value.y
|
|
),
|
|
],
|
|
propertyAnimation.iterations
|
|
)
|
|
);
|
|
break;
|
|
|
|
case Properties.rotate:
|
|
rotateProperty._initDefaultNativeValue(style);
|
|
rotateXProperty._initDefaultNativeValue(style);
|
|
rotateYProperty._initDefaultNativeValue(style);
|
|
|
|
originalValue1 = nativeView.getRotationX();
|
|
originalValue2 = nativeView.getRotationY();
|
|
originalValue3 = nativeView.getRotation();
|
|
|
|
propertyUpdateCallbacks.push(
|
|
checkAnimation(() => {
|
|
propertyAnimation.target.style[
|
|
setLocal
|
|
? rotateXProperty.name
|
|
: rotateXProperty.keyframe
|
|
] = propertyAnimation.value.x;
|
|
propertyAnimation.target.style[
|
|
setLocal
|
|
? rotateYProperty.name
|
|
: rotateYProperty.keyframe
|
|
] = propertyAnimation.value.y;
|
|
propertyAnimation.target.style[
|
|
setLocal
|
|
? rotateProperty.name
|
|
: rotateProperty.keyframe
|
|
] = propertyAnimation.value.z;
|
|
})
|
|
);
|
|
propertyResetCallbacks.push(
|
|
checkAnimation(() => {
|
|
if (setLocal) {
|
|
propertyAnimation.target.style[
|
|
rotateXProperty.name
|
|
] = originalValue1;
|
|
propertyAnimation.target.style[
|
|
rotateYProperty.name
|
|
] = originalValue2;
|
|
propertyAnimation.target.style[
|
|
rotateProperty.name
|
|
] = originalValue3;
|
|
} else {
|
|
propertyAnimation.target.style[
|
|
rotateXProperty.keyframe
|
|
] = originalValue1;
|
|
propertyAnimation.target.style[
|
|
rotateYProperty.keyframe
|
|
] = originalValue2;
|
|
propertyAnimation.target.style[
|
|
rotateProperty.keyframe
|
|
] = originalValue3;
|
|
}
|
|
|
|
if (propertyAnimation.target.nativeViewProtected) {
|
|
propertyAnimation.target[rotateProperty.setNative](
|
|
propertyAnimation.target.style.rotate
|
|
);
|
|
propertyAnimation.target[rotateXProperty.setNative](
|
|
propertyAnimation.target.style.rotateX
|
|
);
|
|
propertyAnimation.target[rotateYProperty.setNative](
|
|
propertyAnimation.target.style.rotateY
|
|
);
|
|
}
|
|
})
|
|
);
|
|
|
|
animators.push(
|
|
createAnimationSet(
|
|
[
|
|
createObjectAnimator(
|
|
nativeView,
|
|
"rotationX",
|
|
propertyAnimation.value.x
|
|
),
|
|
createObjectAnimator(
|
|
nativeView,
|
|
"rotationY",
|
|
propertyAnimation.value.y
|
|
),
|
|
createObjectAnimator(
|
|
nativeView,
|
|
"rotation",
|
|
propertyAnimation.value.z
|
|
),
|
|
],
|
|
propertyAnimation.iterations
|
|
)
|
|
);
|
|
break;
|
|
|
|
case Properties.width:
|
|
case Properties.height: {
|
|
const isVertical: boolean =
|
|
propertyAnimation.property === "height";
|
|
const extentProperty = isVertical
|
|
? heightProperty
|
|
: widthProperty;
|
|
|
|
extentProperty._initDefaultNativeValue(style);
|
|
const nativeArray = Array.create("float", 2);
|
|
let toValue = propertyAnimation.value;
|
|
let parent = propertyAnimation.target.parent as View;
|
|
if (!parent) {
|
|
throw new Error(
|
|
`cannot animate ${propertyAnimation.property} on root view`
|
|
);
|
|
}
|
|
const parentExtent: number = isVertical
|
|
? parent.getMeasuredHeight()
|
|
: parent.getMeasuredWidth();
|
|
toValue =
|
|
PercentLength.toDevicePixels(
|
|
toValue,
|
|
parentExtent,
|
|
parentExtent
|
|
) / screen.mainScreen.scale;
|
|
let nativeHeight: number = isVertical
|
|
? nativeView.getHeight()
|
|
: nativeView.getWidth();
|
|
const targetStyle: string = setLocal
|
|
? extentProperty.name
|
|
: extentProperty.keyframe;
|
|
originalValue1 = nativeHeight / screen.mainScreen.scale;
|
|
nativeArray[0] = originalValue1;
|
|
nativeArray[1] = toValue;
|
|
let extentAnimator = android.animation.ValueAnimator.ofFloat(
|
|
nativeArray
|
|
);
|
|
extentAnimator.addUpdateListener(
|
|
new android.animation.ValueAnimator.AnimatorUpdateListener({
|
|
onAnimationUpdate(
|
|
animator: android.animation.ValueAnimator
|
|
) {
|
|
const argb = (<java.lang.Float>(
|
|
animator.getAnimatedValue()
|
|
)).floatValue();
|
|
propertyAnimation.target.style[
|
|
setLocal
|
|
? extentProperty.name
|
|
: extentProperty.keyframe
|
|
] = argb;
|
|
},
|
|
})
|
|
);
|
|
propertyUpdateCallbacks.push(
|
|
checkAnimation(() => {
|
|
propertyAnimation.target.style[targetStyle] =
|
|
propertyAnimation.value;
|
|
})
|
|
);
|
|
propertyResetCallbacks.push(
|
|
checkAnimation(() => {
|
|
propertyAnimation.target.style[
|
|
targetStyle
|
|
] = originalValue1;
|
|
if (propertyAnimation.target.nativeViewProtected) {
|
|
const setter =
|
|
propertyAnimation.target[
|
|
extentProperty.setNative
|
|
];
|
|
setter(
|
|
propertyAnimation.target.style[
|
|
propertyAnimation.property
|
|
]
|
|
);
|
|
}
|
|
})
|
|
);
|
|
animators.push(extentAnimator);
|
|
break;
|
|
}
|
|
default:
|
|
throw new Error(
|
|
`Animating property '${propertyAnimation.property}' is unsupported`
|
|
);
|
|
}
|
|
|
|
for (let i = 0, length = animators.length; i < length; i++) {
|
|
// Duration
|
|
if (propertyAnimation.duration !== undefined) {
|
|
animators[i].setDuration(propertyAnimation.duration);
|
|
}
|
|
|
|
// Delay
|
|
if (propertyAnimation.delay !== undefined) {
|
|
animators[i].setStartDelay(propertyAnimation.delay);
|
|
}
|
|
|
|
// Repeat Count
|
|
if (
|
|
propertyAnimation.iterations !== undefined &&
|
|
animators[i] instanceof android.animation.ValueAnimator
|
|
) {
|
|
(<android.animation.ValueAnimator>animators[i]).setRepeatCount(
|
|
getAndroidRepeatCount(propertyAnimation.iterations)
|
|
);
|
|
}
|
|
|
|
// Interpolator
|
|
if (propertyAnimation.curve !== undefined) {
|
|
animators[i].setInterpolator(propertyAnimation.curve);
|
|
}
|
|
|
|
if (Trace.isEnabled()) {
|
|
Trace.write(
|
|
"Animator created: " + animators[i],
|
|
Trace.categories.Animation
|
|
);
|
|
}
|
|
}
|
|
|
|
this._animators = this._animators.concat(animators);
|
|
this._propertyUpdateCallbacks = this._propertyUpdateCallbacks.concat(
|
|
propertyUpdateCallbacks
|
|
);
|
|
this._propertyResetCallbacks = this._propertyResetCallbacks.concat(
|
|
propertyResetCallbacks
|
|
);
|
|
}
|
|
}
|