fix(animations): ensure all child elements are rendered before running animations
Closes #9402 Closes #9775
This commit is contained in:
@@ -14,6 +14,8 @@ import {AnimationPlayer} from './animation_player';
|
||||
export class AnimationGroupPlayer implements AnimationPlayer {
|
||||
private _subscriptions: Function[] = [];
|
||||
private _finished = false;
|
||||
private _started = false;
|
||||
|
||||
public parentPlayer: AnimationPlayer = null;
|
||||
|
||||
constructor(private _players: AnimationPlayer[]) {
|
||||
@@ -44,9 +46,19 @@ export class AnimationGroupPlayer implements AnimationPlayer {
|
||||
}
|
||||
}
|
||||
|
||||
init(): void { this._players.forEach(player => player.init()); }
|
||||
|
||||
onDone(fn: Function): void { this._subscriptions.push(fn); }
|
||||
|
||||
play() { this._players.forEach(player => player.play()); }
|
||||
hasStarted() { return this._started; }
|
||||
|
||||
play() {
|
||||
if (!isPresent(this.parentPlayer)) {
|
||||
this.init();
|
||||
}
|
||||
this._started = true;
|
||||
this._players.forEach(player => player.play());
|
||||
}
|
||||
|
||||
pause(): void { this._players.forEach(player => player.pause()); }
|
||||
|
||||
|
||||
@@ -15,6 +15,8 @@ import {scheduleMicroTask} from '../facade/lang';
|
||||
*/
|
||||
export abstract class AnimationPlayer {
|
||||
abstract onDone(fn: Function): void;
|
||||
abstract init(): void;
|
||||
abstract hasStarted(): boolean;
|
||||
abstract play(): void;
|
||||
abstract pause(): void;
|
||||
abstract restart(): void;
|
||||
@@ -31,6 +33,7 @@ export abstract class AnimationPlayer {
|
||||
|
||||
export class NoOpAnimationPlayer implements AnimationPlayer {
|
||||
private _subscriptions: any[] /** TODO #9100 */ = [];
|
||||
private _started = false;
|
||||
public parentPlayer: AnimationPlayer = null;
|
||||
constructor() { scheduleMicroTask(() => this._onFinish()); }
|
||||
/** @internal */
|
||||
@@ -39,7 +42,9 @@ export class NoOpAnimationPlayer implements AnimationPlayer {
|
||||
this._subscriptions = [];
|
||||
}
|
||||
onDone(fn: Function): void { this._subscriptions.push(fn); }
|
||||
play(): void {}
|
||||
hasStarted(): boolean { return this._started; }
|
||||
init(): void {}
|
||||
play(): void { this._started = true; }
|
||||
pause(): void {}
|
||||
restart(): void {}
|
||||
finish(): void { this._onFinish(); }
|
||||
|
||||
@@ -15,6 +15,7 @@ export class AnimationSequencePlayer implements AnimationPlayer {
|
||||
private _activePlayer: AnimationPlayer;
|
||||
private _subscriptions: Function[] = [];
|
||||
private _finished = false;
|
||||
private _started: boolean = false;
|
||||
|
||||
public parentPlayer: AnimationPlayer = null;
|
||||
|
||||
@@ -54,9 +55,19 @@ export class AnimationSequencePlayer implements AnimationPlayer {
|
||||
}
|
||||
}
|
||||
|
||||
init(): void { this._players.forEach(player => player.init()); }
|
||||
|
||||
onDone(fn: Function): void { this._subscriptions.push(fn); }
|
||||
|
||||
play(): void { this._activePlayer.play(); }
|
||||
hasStarted() { return this._started; }
|
||||
|
||||
play(): void {
|
||||
if (!isPresent(this.parentPlayer)) {
|
||||
this.init();
|
||||
}
|
||||
this._started = true;
|
||||
this._activePlayer.play();
|
||||
}
|
||||
|
||||
pause(): void { this._activePlayer.pause(); }
|
||||
|
||||
|
||||
+3
-3
@@ -11,7 +11,7 @@ import {isPresent} from '../facade/lang';
|
||||
|
||||
import {AnimationPlayer} from './animation_player';
|
||||
|
||||
export class ActiveAnimationPlayersMap {
|
||||
export class ViewAnimationMap {
|
||||
private _map = new Map<any, {[key: string]: AnimationPlayer}>();
|
||||
private _allPlayers: AnimationPlayer[] = [];
|
||||
|
||||
@@ -25,9 +25,9 @@ export class ActiveAnimationPlayersMap {
|
||||
}
|
||||
|
||||
findAllPlayersByElement(element: any): AnimationPlayer[] {
|
||||
var players: any[] /** TODO #9100 */ = [];
|
||||
var players: AnimationPlayer[] = [];
|
||||
StringMapWrapper.forEach(
|
||||
this._map.get(element), (player: any /** TODO #9100 */) => players.push(player));
|
||||
this._map.get(element), (player: AnimationPlayer) => players.push(player));
|
||||
return players;
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ import {AnimationPlayer} from '../animation/animation_player';
|
||||
import {AnimationGroupPlayer} from '../animation/animation_group_player';
|
||||
import {AnimationKeyframe} from '../animation/animation_keyframe';
|
||||
import {AnimationStyles} from '../animation/animation_styles';
|
||||
import {ActiveAnimationPlayersMap} from '../animation/active_animation_players_map';
|
||||
import {ViewAnimationMap} from '../animation/view_animation_map';
|
||||
|
||||
var _scope_check: WtfScopeFn = wtfCreateScope(`AppView#check(ascii id)`);
|
||||
|
||||
@@ -54,7 +54,7 @@ export abstract class AppView<T> {
|
||||
|
||||
private _hasExternalHostElement: boolean;
|
||||
|
||||
public activeAnimationPlayers = new ActiveAnimationPlayersMap();
|
||||
public animationPlayers = new ViewAnimationMap();
|
||||
|
||||
public context: T;
|
||||
|
||||
@@ -74,20 +74,26 @@ export abstract class AppView<T> {
|
||||
|
||||
cancelActiveAnimation(element: any, animationName: string, removeAllAnimations: boolean = false) {
|
||||
if (removeAllAnimations) {
|
||||
this.activeAnimationPlayers.findAllPlayersByElement(element).forEach(
|
||||
player => player.destroy());
|
||||
this.animationPlayers.findAllPlayersByElement(element).forEach(player => player.destroy());
|
||||
} else {
|
||||
var player = this.activeAnimationPlayers.find(element, animationName);
|
||||
var player = this.animationPlayers.find(element, animationName);
|
||||
if (isPresent(player)) {
|
||||
player.destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
registerAndStartAnimation(element: any, animationName: string, player: AnimationPlayer): void {
|
||||
this.activeAnimationPlayers.set(element, animationName, player);
|
||||
player.onDone(() => { this.activeAnimationPlayers.remove(element, animationName); });
|
||||
player.play();
|
||||
queueAnimation(element: any, animationName: string, player: AnimationPlayer): void {
|
||||
this.animationPlayers.set(element, animationName, player);
|
||||
player.onDone(() => { this.animationPlayers.remove(element, animationName); });
|
||||
}
|
||||
|
||||
triggerQueuedAnimations() {
|
||||
this.animationPlayers.getAllPlayers().forEach(player => {
|
||||
if (!player.hasStarted()) {
|
||||
player.play();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
create(context: T, givenProjectableNodes: Array<any|any[]>, rootSelectorOrNode: string|any):
|
||||
@@ -201,10 +207,10 @@ export abstract class AppView<T> {
|
||||
this.destroyInternal();
|
||||
this.dirtyParentQueriesInternal();
|
||||
|
||||
if (this.activeAnimationPlayers.length == 0) {
|
||||
if (this.animationPlayers.length == 0) {
|
||||
this.renderer.destroyView(hostElement, this.allNodes);
|
||||
} else {
|
||||
var player = new AnimationGroupPlayer(this.activeAnimationPlayers.getAllPlayers());
|
||||
var player = new AnimationGroupPlayer(this.animationPlayers.getAllPlayers());
|
||||
player.onDone(() => { this.renderer.destroyView(hostElement, this.allNodes); });
|
||||
}
|
||||
}
|
||||
@@ -221,10 +227,10 @@ export abstract class AppView<T> {
|
||||
|
||||
detach(): void {
|
||||
this.detachInternal();
|
||||
if (this.activeAnimationPlayers.length == 0) {
|
||||
if (this.animationPlayers.length == 0) {
|
||||
this.renderer.detachView(this.flatRootNodes);
|
||||
} else {
|
||||
var player = new AnimationGroupPlayer(this.activeAnimationPlayers.getAllPlayers());
|
||||
var player = new AnimationGroupPlayer(this.animationPlayers.getAllPlayers());
|
||||
player.onDone(() => { this.renderer.detachView(this.flatRootNodes); });
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user