mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-08-15 19:26:42 +08:00

* feat: add 3d rotation * chore: fix build errors * chore: fix tslint errors * chore: add @types/chai dev dep * chore: unused import cleanup * chore: update tests for x,y rotation * chore: rebase upstream/master * fix: iOS Affine Transform test verification * feat(css): Added optional css-tree parser (#8076) * feat(css): Added optional css-tree parser * test: css-tree parser compat tests * test: more css-tree compat tests * feat(dialogs): Setting the size of popup dialog thru dialog options (#8041) * Added iOS specific height and width attributes to ShowModalOptions * Set the height and width of the popup dialog to the presenting controller * dialog options ios attributes presentationStyle, height & width are made optional * Updated NativeScript.api.md for public API changes * Update with git properties * Public API * CLA update * fix: use iOS native-helper for 3d-rotate * test: Fix tests using _getTransformMismatchError * fix: view.__hasTransfrom not set updating properly * test: fix css-animations test page Co-authored-by: Alexander Vakrilov <alexander.vakrilov@gmail.com> Co-authored-by: Darin Dimitrov <darin.dimitrov@gmail.com> Co-authored-by: Shailesh Lolam <slolam@live.com> Co-authored-by: Dimitar Topuzov <dtopuzov@gmail.com>
559 lines
26 KiB
TypeScript
559 lines
26 KiB
TypeScript
// Types.
|
|
import { AnimationDefinitionInternal, AnimationPromise, PropertyAnimation } from "./animation-common";
|
|
import { View } from "../core/view";
|
|
|
|
// Requires
|
|
import {
|
|
AnimationBase, Properties, CubicBezierAnimationCurve, Color, traceWrite,
|
|
traceEnabled, traceCategories, traceType
|
|
} from "./animation-common";
|
|
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 (traceEnabled()) {
|
|
traceWrite("Animation curve resolved to android.view.animation.AccelerateInterpolator(1).", traceCategories.Animation);
|
|
}
|
|
|
|
return easeIn();
|
|
case "easeOut":
|
|
if (traceEnabled()) {
|
|
traceWrite("Animation curve resolved to android.view.animation.DecelerateInterpolator(1).", traceCategories.Animation);
|
|
}
|
|
|
|
return easeOut();
|
|
case "easeInOut":
|
|
if (traceEnabled()) {
|
|
traceWrite("Animation curve resolved to android.view.animation.AccelerateDecelerateInterpolator().", traceCategories.Animation);
|
|
}
|
|
|
|
return easeInOut();
|
|
case "linear":
|
|
if (traceEnabled()) {
|
|
traceWrite("Animation curve resolved to android.view.animation.LinearInterpolator().", traceCategories.Animation);
|
|
}
|
|
|
|
return linear();
|
|
case "spring":
|
|
if (traceEnabled()) {
|
|
traceWrite("Animation curve resolved to android.view.animation.BounceInterpolator().", traceCategories.Animation);
|
|
}
|
|
|
|
return bounce();
|
|
case "ease":
|
|
return (<any>androidx).core.view.animation.PathInterpolatorCompat.create(0.25, 0.1, 0.25, 1.0);
|
|
default:
|
|
if (traceEnabled()) {
|
|
traceWrite("Animation curve resolved to original: " + curve, traceCategories.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 (traceEnabled()) {
|
|
traceWrite("MainAnimatorListener.onAndroidAnimationStart(" + animator + ")", traceCategories.Animation);
|
|
}
|
|
},
|
|
onAnimationRepeat: function (animator: android.animation.Animator): void {
|
|
if (traceEnabled()) {
|
|
traceWrite("MainAnimatorListener.onAnimationRepeat(" + animator + ")", traceCategories.Animation);
|
|
}
|
|
},
|
|
onAnimationEnd: function (animator: android.animation.Animator): void {
|
|
if (traceEnabled()) {
|
|
traceWrite("MainAnimatorListener.onAnimationEnd(" + animator + ")", traceCategories.Animation);
|
|
}
|
|
const thisRef = that.get();
|
|
if (thisRef) {
|
|
thisRef._onAndroidAnimationEnd();
|
|
}
|
|
},
|
|
onAnimationCancel: function (animator: android.animation.Animator): void {
|
|
if (traceEnabled()) {
|
|
traceWrite("MainAnimatorListener.onAnimationCancel(" + animator + ")", traceCategories.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) {
|
|
traceWrite("Animation is not currently playing.", traceCategories.Animation, traceType.warn);
|
|
|
|
return;
|
|
}
|
|
|
|
traceWrite("Cancelling AnimatorSet.", traceCategories.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 (traceEnabled()) {
|
|
traceWrite("Starting " + this._nativeAnimatorsArray.length + " animations " + (this._playSequentially ? "sequentially." : "together."), traceCategories.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 (traceEnabled()) {
|
|
traceWrite("Creating ObjectAnimator(s) for animation: " + Animation._getAnimationInfo(propertyAnimation) + "...", traceCategories.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 (traceEnabled()) {
|
|
traceWrite("Animator created: " + animators[i], traceCategories.Animation);
|
|
}
|
|
}
|
|
|
|
this._animators = this._animators.concat(animators);
|
|
this._propertyUpdateCallbacks = this._propertyUpdateCallbacks.concat(propertyUpdateCallbacks);
|
|
this._propertyResetCallbacks = this._propertyResetCallbacks.concat(propertyResetCallbacks);
|
|
}
|
|
}
|