Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion apps/automated/src/ui/animation/css-animation-tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ export function test_ReadIterations() {
let animation = createAnimationFromCSS('.test { animation-iteration-count: 5; }', 'test');
TKUnit.assertEqual(animation.iterations, 5);
animation = createAnimationFromCSS('.test { animation-iteration-count: infinite; }', 'test');
TKUnit.assertEqual(animation.iterations, Number.MAX_VALUE);
TKUnit.assertEqual(animation.iterations, Number.POSITIVE_INFINITY);
}

export function test_ReadFillMode() {
Expand Down
281 changes: 115 additions & 166 deletions packages/core/ui/animation/index.android.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,6 @@ const easeInOut = lazy(() => new android.view.animation.AccelerateDecelerateInte
const linear = lazy(() => new android.view.animation.LinearInterpolator());
const bounce = lazy(() => new android.view.animation.BounceInterpolator());

const keyPrefix = 'ui.animation.';
const 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':
Expand Down Expand Up @@ -178,27 +168,27 @@ export class Animation extends AnimationBase {
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>();
const animationFinishedPromise = super.play();

for (let i = 0, length = this._propertyAnimations.length; i < length; i++) {
this._createAnimators(this._propertyAnimations[i]);
}
if (!this._animatorSet) {
this._animators = new Array<android.animation.Animator>();
this._propertyUpdateCallbacks = new Array<Function>();
this._propertyResetCallbacks = new Array<Function>();

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];
}
for (let i = 0, length = this._propertyAnimations.length; i < length; i++) {
this._createAnimators(this._propertyAnimations[i]);
}

this._animatorSet = new android.animation.AnimatorSet();
this._animatorSet.addListener(this._animatorListener);
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];
}

return this._play();
this._animatorSet = new android.animation.AnimatorSet();
this._animatorSet.addListener(this._animatorListener);
}
this._play();
return animationFinishedPromise;
}

public cancel(): void {
Expand All @@ -217,9 +207,7 @@ export class Animation extends AnimationBase {
return _resolveAnimationCurve(curve);
}

private _play(): AnimationPromise {
const animationFinishedPromise = super.play();

private _play(): void {
if (Device.sdkVersion <= '23') {
this._animatorSet = new android.animation.AnimatorSet();
this._animatorSet.addListener(this._animatorListener);
Expand All @@ -239,8 +227,6 @@ export class Animation extends AnimationBase {

this._animatorSet.setupStartValues();
this._animatorSet.start();

return animationFinishedPromise;
}

private _onAndroidAnimationEnd() {
Expand Down Expand Up @@ -300,43 +286,26 @@ export class Animation extends AnimationBase {
let originalValue3;
const density = layout.getDisplayDensity();

const key = propertyKeys[propertyAnimation.property];
if (key) {
propertyAnimation.target[key] = propertyAnimation;
}
function checkAnimation(cb) {
return () => {
if (propertyAnimation.target[key] === propertyAnimation) {
delete propertyAnimation.target[key];
cb();
}
};
}

const 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);
}
})
);
propertyUpdateCallbacks.push(() => {
propertyAnimation.target.style[setLocal ? opacityProperty.name : opacityProperty.keyframe] = propertyAnimation.value;
});
propertyResetCallbacks.push(() => {
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;

Expand All @@ -358,24 +327,20 @@ export class Animation extends AnimationBase {
})
);

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);
}
})
);
propertyUpdateCallbacks.push(() => {
propertyAnimation.target.style[setLocal ? backgroundColorProperty.name : backgroundColorProperty.keyframe] = propertyAnimation.value;
});
propertyResetCallbacks.push(() => {
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;
}
Expand All @@ -386,29 +351,25 @@ export class Animation extends AnimationBase {
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);
}
})
);
propertyUpdateCallbacks.push(() => {
propertyAnimation.target.style[setLocal ? translateXProperty.name : translateXProperty.keyframe] = propertyAnimation.value.x;
propertyAnimation.target.style[setLocal ? translateYProperty.name : translateYProperty.keyframe] = propertyAnimation.value.y;
});

propertyResetCallbacks.push(() => {
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;
Expand All @@ -420,29 +381,25 @@ export class Animation extends AnimationBase {
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);
}
})
);
propertyUpdateCallbacks.push(() => {
propertyAnimation.target.style[setLocal ? scaleXProperty.name : scaleXProperty.keyframe] = propertyAnimation.value.x;
propertyAnimation.target.style[setLocal ? scaleYProperty.name : scaleYProperty.keyframe] = propertyAnimation.value.y;
});

propertyResetCallbacks.push(() => {
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;
Expand All @@ -456,32 +413,28 @@ export class Animation extends AnimationBase {
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);
}
})
);
propertyUpdateCallbacks.push(() => {
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(() => {
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;
Expand Down Expand Up @@ -514,20 +467,16 @@ export class Animation extends AnimationBase {
},
})
);
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]);
}
})
);
propertyUpdateCallbacks.push(() => {
propertyAnimation.target.style[targetStyle] = propertyAnimation.value;
});
propertyResetCallbacks.push(() => {
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;
}
Expand Down
11 changes: 10 additions & 1 deletion packages/core/ui/animation/index.ios.ts
Original file line number Diff line number Diff line change
Expand Up @@ -464,10 +464,19 @@ export class Animation extends AnimationBase {
private static _createGroupAnimation(args: AnimationInfo, animation: PropertyAnimation) {
const groupAnimation = CAAnimationGroup.new();
groupAnimation.duration = args.duration;
if (args.repeatCount !== undefined) {
groupAnimation.repeatCount = args.repeatCount;
}
if (args.delay !== undefined) {
groupAnimation.beginTime = CACurrentMediaTime() + args.delay;
}
if (animation.curve !== undefined) {
groupAnimation.timingFunction = animation.curve;
}
const animations = NSMutableArray.alloc<CAAnimation>().initWithCapacity(3);

args.subPropertiesToAnimate.forEach((property) => {
const basicAnimationArgs = { ...args };
const basicAnimationArgs = { ...args, duration: undefined, repeatCount: undefined, delay: undefined, curve: undefined };
basicAnimationArgs.propertyNameToAnimate = `${args.propertyNameToAnimate}.${property}`;
basicAnimationArgs.fromValue = args.fromValue[property];
basicAnimationArgs.toValue = args.toValue[property];
Expand Down
Loading