Skip to content

Commit d517c68

Browse files
committed
Merge pull request NativeScript#791 from NativeScript/hristov/issue-774
Fixed: If an Animation instance is played more than once, the same pr…
2 parents 845bd65 + 911e5fd commit d517c68

File tree

7 files changed

+135
-82
lines changed

7 files changed

+135
-82
lines changed

apps/animations/main-page.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@ export function onSlideOut(args: observable.EventData) {
3838

3939
panelAnimation = panel.createAnimation({ opacity: 0, scale: { x: 0.5, y: 0.5 }, rotate: -360, backgroundColor: new colorModule.Color("red"), duration: vm.duration, iterations: vm.iterations });
4040

41-
buttonAnimation.play().finished
42-
.then(() => panelAnimation.play().finished)
41+
buttonAnimation.play()
42+
.then(() => panelAnimation.play())
4343
.catch((e) => console.log(e.message));
4444
}
4545

@@ -56,8 +56,8 @@ export function onSlideIn(args: observable.EventData) {
5656
]
5757
buttonAnimation = new animationModule.Animation(buttonAnimations, vm.playSequentially);
5858

59-
panelAnimation.play().finished
60-
.then(() => buttonAnimation.play().finished)
59+
panelAnimation.play()
60+
.then(() => buttonAnimation.play())
6161
.catch((e) => console.log(e.message));
6262
}
6363

apps/tests/ui/animation/animation-tests.ts

Lines changed: 115 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ export var test_CancellingAnimation = function (done) {
8181
// # Cancelling animation
8282
// ``` JavaScript
8383
var animation1 = label.createAnimation({ translate: { x: 100, y: 100 } });
84-
animation1.play().finished
84+
animation1.play()
8585
.then(() => {
8686
////console.log("Animation finished");
8787
// <hide>
@@ -145,51 +145,51 @@ export var test_ChainingAnimations = function (done) {
145145
// </snippet>
146146
}
147147

148-
//export var test_ReusingAnimations = function (done) {
149-
// var mainPage: pageModule.Page;
150-
// var label: labelModule.Label;
151-
// var pageFactory = function (): pageModule.Page {
152-
// label = new labelModule.Label();
153-
// label.text = "label";
154-
// var stackLayout = new stackLayoutModule.StackLayout();
155-
// stackLayout.addChild(label);
156-
// mainPage = new pageModule.Page();
157-
// mainPage.content = stackLayout;
158-
// return mainPage;
159-
// };
160-
161-
// helper.navigate(pageFactory);
162-
// TKUnit.waitUntilReady(() => { return label.isLoaded });
163-
164-
// // <snippet module="ui/animation" title="animation">
165-
// // # Reusing animations
166-
// // ``` JavaScript
167-
// var animation1 = label.createAnimation({ translate: { x: 100, y: 100 } });
168-
// var animation2 = label.createAnimation({ translate: { x: 0, y: 0 } });
169-
170-
// animation1.play().finished
171-
// .then(() => animation1.play().finished)
172-
// .then(() => animation1.play().finished)
173-
// .then(() => animation2.play().finished)
174-
// .then(() => animation1.play().finished)
175-
// .then(() => animation2.play().finished)
176-
// .then(() => {
177-
// ////console.log("Animation finished");
178-
// // <hide>
179-
// helper.goBack();
180-
// done();
181-
// // </hide>
182-
// })
183-
// .catch((e) => {
184-
// console.log(e.message);
185-
// // <hide>
186-
// helper.goBack();
187-
// done(e);
188-
// // </hide>
189-
// });
190-
// // ```
191-
// // </snippet>
192-
//}
148+
export var test_ReusingAnimations = function (done) {
149+
var mainPage: pageModule.Page;
150+
var label: labelModule.Label;
151+
var pageFactory = function (): pageModule.Page {
152+
label = new labelModule.Label();
153+
label.text = "label";
154+
var stackLayout = new stackLayoutModule.StackLayout();
155+
stackLayout.addChild(label);
156+
mainPage = new pageModule.Page();
157+
mainPage.content = stackLayout;
158+
return mainPage;
159+
};
160+
161+
helper.navigate(pageFactory);
162+
TKUnit.waitUntilReady(() => { return label.isLoaded });
163+
164+
// <snippet module="ui/animation" title="animation">
165+
// # Reusing animations
166+
// ``` JavaScript
167+
var animation1 = label.createAnimation({ translate: { x: 100, y: 100 } });
168+
var animation2 = label.createAnimation({ translate: { x: 0, y: 0 } });
169+
170+
animation1.play()
171+
.then(() => animation2.play())
172+
.then(() => animation1.play())
173+
.then(() => animation2.play())
174+
.then(() => animation1.play())
175+
.then(() => animation2.play())
176+
.then(() => {
177+
////console.log("Animation finished");
178+
// <hide>
179+
helper.goBack();
180+
done();
181+
// </hide>
182+
})
183+
.catch((e) => {
184+
console.log(e.message);
185+
// <hide>
186+
helper.goBack();
187+
done(e);
188+
// </hide>
189+
});
190+
// ```
191+
// </snippet>
192+
}
193193

194194
export var test_AnimatingMultipleViews = function (done) {
195195
var mainPage: pageModule.Page;
@@ -223,7 +223,7 @@ export var test_AnimatingMultipleViews = function (done) {
223223
{ target: label3, translate: { x: 200, y: 200 }, duration: 1000, delay: 666 },
224224
];
225225
var a = new animation.Animation(animations);
226-
a.play().finished
226+
a.play()
227227
.then(() => {
228228
////console.log("Animations finished");
229229
// <hide>
@@ -404,10 +404,13 @@ export var test_AnimationsAreAlwaysPlayed = function (done) {
404404
var animation1 = label.createAnimation({ opacity: 0 });
405405
var animation2 = label.createAnimation({ opacity: 1 });
406406

407-
animation1.play().finished
408-
.then(() => animation2.play().finished)
407+
animation1.play()
408+
.then(() => {
409+
TKUnit.assert(label.opacity === 0, `Label opacity should be 0 after first animation, actual value is ${label.opacity}.`);
410+
return animation2.play()
411+
})
409412
.then(() => {
410-
TKUnit.assert(label.opacity === 1, `Label opacity expected vaue is 1, actual value is ${label.opacity}.`);
413+
TKUnit.assert(label.opacity === 1, `Label opacity should be 1 after second animation, actual value is ${label.opacity}.`);
411414
helper.goBack();
412415
done();
413416
})
@@ -417,3 +420,65 @@ export var test_AnimationsAreAlwaysPlayed = function (done) {
417420
done(e);
418421
});
419422
}
423+
424+
export var test_PlayPromiseIsResolvedWhenAnimationFinishes = function (done) {
425+
var mainPage: pageModule.Page;
426+
var label: labelModule.Label;
427+
var pageFactory = function (): pageModule.Page {
428+
label = new labelModule.Label();
429+
label.text = "label";
430+
var stackLayout = new stackLayoutModule.StackLayout();
431+
stackLayout.addChild(label);
432+
mainPage = new pageModule.Page();
433+
mainPage.content = stackLayout;
434+
return mainPage;
435+
};
436+
437+
helper.navigate(pageFactory);
438+
TKUnit.waitUntilReady(() => { return label.isLoaded });
439+
440+
var animation = label.createAnimation({ opacity: 0, duration: 1000 });
441+
442+
animation.play()
443+
.then(function onResolved() {
444+
TKUnit.assert(animation.isPlaying === false, "Animation.isPlaying should be false when animation play promise is resolved.");
445+
helper.goBack();
446+
done();
447+
}, function onRejected(e) {
448+
TKUnit.assert(1 === 2, "Animation play promise should be resolved, not rejected.");
449+
helper.goBack();
450+
done(e);
451+
});
452+
}
453+
454+
export var test_PlayPromiseIsRejectedWhenAnimationIsCancelled = function (done) {
455+
var mainPage: pageModule.Page;
456+
var label: labelModule.Label;
457+
var pageFactory = function (): pageModule.Page {
458+
label = new labelModule.Label();
459+
label.text = "label";
460+
var stackLayout = new stackLayoutModule.StackLayout();
461+
stackLayout.addChild(label);
462+
mainPage = new pageModule.Page();
463+
mainPage.content = stackLayout;
464+
return mainPage;
465+
};
466+
467+
helper.navigate(pageFactory);
468+
TKUnit.waitUntilReady(() => { return label.isLoaded });
469+
470+
var animation = label.createAnimation({ opacity: 0, duration: 1000 });
471+
472+
animation.play()
473+
.then(function onResolved() {
474+
TKUnit.assert(1 === 2, "Animation play promise should be rejected, not resolved.");
475+
helper.goBack();
476+
done();
477+
}, function onRejected(e) {
478+
TKUnit.assert(animation.isPlaying === false, "Animation.isPlaying should be false when animation play promise is rejected.");
479+
helper.goBack();
480+
done();
481+
});
482+
483+
animation.cancel();
484+
}

ui/animation/animation-common.ts

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,19 @@ export class Animation implements definition.Animation {
2626
private _isPlaying: boolean;
2727
private _resolve;
2828
private _reject;
29-
private _animationFinishedPromise: Promise<void>;
3029

31-
public play(): Animation {
30+
public play(): Promise<void> {
3231
if (this.isPlaying) {
3332
throw new Error("Animation is already playing.");
3433
}
3534

35+
var animationFinishedPromise = new Promise<void>((resolve, reject) => {
36+
this._resolve = resolve;
37+
this._reject = reject;
38+
});
39+
3640
this._isPlaying = true;
37-
return this;
41+
return animationFinishedPromise;
3842
}
3943

4044
public cancel(): void {
@@ -43,10 +47,6 @@ export class Animation implements definition.Animation {
4347
}
4448
}
4549

46-
public get finished(): Promise<void> {
47-
return this._animationFinishedPromise;
48-
}
49-
5050
public get isPlaying(): boolean {
5151
return this._isPlaying;
5252
}
@@ -70,11 +70,6 @@ export class Animation implements definition.Animation {
7070
trace.write("Created " + this._propertyAnimations.length + " individual property animations.", trace.categories.Animation);
7171

7272
this._playSequentially = playSequentially;
73-
var that = this;
74-
this._animationFinishedPromise = new Promise<void>((resolve, reject) => {
75-
that._resolve = resolve;
76-
that._reject = reject;
77-
});
7873
}
7974

8075
public _resolveAnimationFinishedPromise() {

ui/animation/animation.android.ts

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ export class Animation extends common.Animation implements definition.Animation
1818
private _propertyUpdateCallbacks: Array<Function>;
1919
private _propertyResetCallbacks: Array<Function>;
2020

21-
public play(): Animation {
22-
super.play();
21+
public play(): Promise<void> {
22+
var animationFinishedPromise = super.play();
2323

2424
var i: number;
2525
var length: number;
@@ -34,12 +34,6 @@ export class Animation extends common.Animation implements definition.Animation
3434
this._createAnimators(this._propertyAnimations[i]);
3535
}
3636

37-
if (this._animators.length === 0) {
38-
trace.write("Nothing to animate.", trace.categories.Animation);
39-
this._resolveAnimationFinishedPromise();
40-
return this;
41-
}
42-
4337
this._nativeAnimatorsArray = java.lang.reflect.Array.newInstance(android.animation.Animator.class, this._animators.length);
4438
i = 0;
4539
length = this._animators.length;
@@ -58,7 +52,7 @@ export class Animation extends common.Animation implements definition.Animation
5852

5953
trace.write("Starting " + this._nativeAnimatorsArray.length + " animations " + (this._playSequentially ? "sequentially." : "together."), trace.categories.Animation);
6054
this._animatorSet.start();
61-
return this;
55+
return animationFinishedPromise;
6256
}
6357

6458
public cancel(): void {

ui/animation/animation.d.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,9 +72,8 @@
7272
*/
7373
export class Animation {
7474
constructor(animationDefinitions: Array<AnimationDefinition>, playSequentially?: boolean);
75-
public play: () => Animation;
75+
public play: () => Promise<void>;
7676
public cancel: () => void;
77-
public finished: Promise<void>;
7877
public isPlaying: boolean;
7978
}
8079
}

ui/animation/animation.ios.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,14 +46,14 @@ export class Animation extends common.Animation implements definition.Animation
4646
private _cancelledAnimations: number;
4747
private _mergedPropertyAnimations: Array<common.PropertyAnimation>;
4848

49-
public play(): Animation {
50-
super.play();
49+
public play(): Promise<void> {
50+
var animationFinishedPromise = super.play();
5151

5252
this._finishedAnimations = 0;
5353
this._cancelledAnimations = 0;
54-
this._iOSAnimationFunction();
5554

56-
return this;
55+
this._iOSAnimationFunction();
56+
return animationFinishedPromise;
5757
}
5858

5959
public cancel(): void {

ui/core/view-common.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1099,7 +1099,7 @@ export class View extends proxy.ProxyObject implements definition.View {
10991099
}
11001100

11011101
public animate(animation: animationModule.AnimationDefinition): Promise<void> {
1102-
return this.createAnimation(animation).play().finished;
1102+
return this.createAnimation(animation).play();
11031103
}
11041104

11051105
public createAnimation(animation: animationModule.AnimationDefinition): animationModule.Animation {

0 commit comments

Comments
 (0)