Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 2bd2d16

Browse files
author
Tsvetan Raikov
committed
Added animations support in Angular 2 RC3
1 parent 99394b3 commit 2bd2d16

16 files changed

+461
-20
lines changed
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { AnimationKeyframe } from '@angular/core/src/animation/animation_keyframe';
2+
import { AnimationPlayer } from '@angular/core/src/animation/animation_player';
3+
import { AnimationStyles } from '@angular/core/src/animation/animation_styles';
4+
import { AnimationDriver } from '@angular/core/src/animation/animation_driver';
5+
import { NativeScriptAnimationPlayer } from './animation-player';
6+
import {View} from "ui/core/view";
7+
import styleProperty = require('ui/styling/style-property');
8+
9+
export class NativeScriptAnimationDriver implements AnimationDriver {
10+
11+
computeStyle(element: any, prop: string): string {
12+
return (<View>element).style._getValue(styleProperty.getPropertyByCssName(prop));
13+
}
14+
15+
animate(element: any, startingStyles: AnimationStyles, keyframes: AnimationKeyframe[], duration: number, delay: number, easing: string): AnimationPlayer {
16+
return new NativeScriptAnimationPlayer(element, keyframes, duration, delay, easing);
17+
}
18+
}
Lines changed: 240 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,240 @@
1+
import { AnimationKeyframe } from '@angular/core/src/animation/animation_keyframe';
2+
import { AnimationPlayer } from '@angular/core/src/animation/animation_player';
3+
import { AnimationStyles } from '@angular/core/src/animation/animation_styles';
4+
import { AnimationDriver } from '@angular/core/src/animation/animation_driver';
5+
import { KeyframeAnimation, KeyframeAnimationInfo, KeyframeInfo, KeyframeDeclaration } from 'ui/animation/keyframe-animation';
6+
import { View } from "ui/core/view";
7+
import enums = require("ui/enums");
8+
import styleProperty = require('ui/styling/style-property');
9+
import observable = require('ui/core/dependency-observable');
10+
import types = require("utils/types");
11+
12+
export class NativeScriptAnimationPlayer implements AnimationPlayer {
13+
14+
public parentPlayer: AnimationPlayer;
15+
16+
private _subscriptions: Function[] = [];
17+
private _finished = false;
18+
private animation: KeyframeAnimation;
19+
private target: View;
20+
21+
constructor(element: Node, keyframes: AnimationKeyframe[], duration: number, delay: number, easing: string) {
22+
23+
this.parentPlayer = null;
24+
25+
if (duration === 0) {
26+
duration = 0.01;
27+
}
28+
29+
if (!(element instanceof View)) {
30+
throw new Error("NativeScript: Can animate only Views!");
31+
}
32+
33+
this.target = <any>element;
34+
35+
let keyframeAnimationInfo = new KeyframeAnimationInfo();
36+
keyframeAnimationInfo.duration = duration;
37+
keyframeAnimationInfo.delay = delay;
38+
keyframeAnimationInfo.iterations = 1;
39+
keyframeAnimationInfo.curve = easing ? NativeScriptAnimationPlayer.animationTimingFunctionConverter(easing) : enums.AnimationCurve.ease;
40+
keyframeAnimationInfo.keyframes = new Array<KeyframeInfo>();
41+
keyframeAnimationInfo.isForwards = true;
42+
43+
for (let keyframe of keyframes) {
44+
let keyframeInfo = <KeyframeInfo>{};
45+
keyframeInfo.duration = keyframe.offset;
46+
keyframeInfo.declarations = new Array<KeyframeDeclaration>();
47+
for (let style of keyframe.styles.styles) {
48+
for (let substyle in style) {
49+
let value = style[substyle];
50+
let property = styleProperty.getPropertyByCssName(substyle);
51+
if (property) {
52+
if (typeof value === "string" && property.valueConverter) {
53+
value = property.valueConverter(<string>value);
54+
}
55+
keyframeInfo.declarations.push({ property: property.name, value: value })
56+
}
57+
else if (typeof value === "string" && substyle === "transform") {
58+
NativeScriptAnimationPlayer.parseTransform(<string>value, keyframeInfo);
59+
}
60+
}
61+
}
62+
keyframeAnimationInfo.keyframes.push(keyframeInfo)
63+
}
64+
65+
this.animation = KeyframeAnimation.keyframeAnimationFromInfo(keyframeAnimationInfo, observable.ValueSource.VisualState);
66+
}
67+
68+
onDone(fn: Function): void { this._subscriptions.push(fn); }
69+
70+
private _onFinish() {
71+
if (!this._finished) {
72+
this._finished = true;
73+
this._subscriptions.forEach(fn => fn());
74+
this._subscriptions = [];
75+
}
76+
}
77+
78+
play(): void {
79+
if (this.animation) {
80+
this.animation.play(this.target)
81+
.then(() => { this._onFinish(); })
82+
.catch((e) => {});
83+
}
84+
}
85+
86+
pause(): void {
87+
throw new Error("AnimationPlayer.pause method is not supported!");
88+
}
89+
90+
finish(): void {
91+
throw new Error("AnimationPlayer.finish method is not supported!");
92+
}
93+
94+
reset(): void {
95+
if (this.animation && this.animation.isPlaying) {
96+
this.animation.cancel();
97+
}
98+
}
99+
100+
restart(): void {
101+
this.reset();
102+
this.play();
103+
}
104+
105+
destroy(): void {
106+
this.reset();
107+
this._onFinish();
108+
}
109+
110+
setPosition(p: any): void {
111+
throw new Error("AnimationPlayer.setPosition method is not supported!");
112+
}
113+
114+
getPosition(): number {
115+
return 0;
116+
}
117+
118+
static animationTimingFunctionConverter(value): any {
119+
switch (value) {
120+
case "ease":
121+
return enums.AnimationCurve.ease;
122+
case "linear":
123+
return enums.AnimationCurve.linear;
124+
case "ease-in":
125+
return enums.AnimationCurve.easeIn;
126+
case "ease-out":
127+
return enums.AnimationCurve.easeOut;
128+
case "ease-in-out":
129+
return enums.AnimationCurve.easeInOut;
130+
case "spring":
131+
return enums.AnimationCurve.spring;
132+
default:
133+
if (value.indexOf("cubic-bezier(") === 0) {
134+
let bezierArr = value.substring(13).split(/[,]+/);
135+
if (bezierArr.length !== 4) {
136+
throw new Error("Invalid value for animation: " + value);
137+
}
138+
return enums.AnimationCurve.cubicBezier(
139+
NativeScriptAnimationPlayer.bezieArgumentConverter(bezierArr[0]),
140+
NativeScriptAnimationPlayer.bezieArgumentConverter(bezierArr[1]),
141+
NativeScriptAnimationPlayer.bezieArgumentConverter(bezierArr[2]),
142+
NativeScriptAnimationPlayer.bezieArgumentConverter(bezierArr[3]));
143+
}
144+
else {
145+
throw new Error("Invalid value for animation: " + value);
146+
}
147+
}
148+
}
149+
150+
static bezieArgumentConverter(value): number {
151+
let result = parseFloat(value);
152+
result = Math.max(0.0, result);
153+
result = Math.min(1.0, result);
154+
return result;
155+
}
156+
157+
static transformConverter(value: any): Object {
158+
if (value === "none") {
159+
let operations = {};
160+
operations[value] = value;
161+
return operations;
162+
}
163+
else if (types.isString(value)) {
164+
let operations = {};
165+
let operator = "";
166+
let pos = 0;
167+
while (pos < value.length) {
168+
if (value[pos] === " " || value[pos] === ",") {
169+
pos ++;
170+
}
171+
else if (value[pos] === "(") {
172+
let start = pos + 1;
173+
while (pos < value.length && value[pos] !== ")") {
174+
pos ++;
175+
}
176+
let operand = value.substring(start, pos);
177+
operations[operator] = operand.trim();
178+
operator = "";
179+
pos ++;
180+
}
181+
else {
182+
operator += value[pos ++];
183+
}
184+
}
185+
return operations;
186+
}
187+
else {
188+
return undefined;
189+
}
190+
}
191+
192+
static parseTransform(value: string, animationInfo: KeyframeInfo) {
193+
let newTransform = NativeScriptAnimationPlayer.transformConverter(value);
194+
let array = new Array<styleProperty.KeyValuePair<styleProperty.Property, any>>();
195+
let values = undefined;
196+
for (let transform in newTransform) {
197+
switch (transform) {
198+
case "scaleX":
199+
animationInfo.declarations.push({ property: "scale", value: { x: parseFloat(newTransform[transform]), y: 1 } });
200+
break;
201+
case "scaleY":
202+
animationInfo.declarations.push({ property: "scale", value: { x: 1, y: parseFloat(newTransform[transform]) } });
203+
break;
204+
case "scale":
205+
case "scale3d":
206+
values = newTransform[transform].split(",");
207+
if (values.length === 2 || values.length === 3) {
208+
animationInfo.declarations.push({ property: "scale", value: { x: parseFloat(values[0]), y: parseFloat(values[1]) } });
209+
}
210+
break;
211+
case "translateX":
212+
animationInfo.declarations.push({ property: "translate", value: { x: parseFloat(newTransform[transform]), y: 0 } });
213+
break;
214+
case "translateY":
215+
animationInfo.declarations.push({ property: "translate", value: { x: 0, y: parseFloat(newTransform[transform]) } });
216+
break;
217+
case "translate":
218+
case "translate3d":
219+
values = newTransform[transform].split(",");
220+
if (values.length === 2 || values.length === 3) {
221+
animationInfo.declarations.push({ property: "translate", value: { x: parseFloat(values[0]), y: parseFloat(values[1]) } });
222+
}
223+
break;
224+
case "rotate":
225+
let text = newTransform[transform];
226+
let val = parseFloat(text);
227+
if (text.slice(-3) === "rad") {
228+
val = val * (180.0 / Math.PI);
229+
}
230+
animationInfo.declarations.push({ property: "rotate", value: val });
231+
case "none":
232+
animationInfo.declarations.push({ property: "scale", value: { x: 1, y: 1 } });
233+
animationInfo.declarations.push({ property: "translate", value: { x: 0, y: 0 } });
234+
animationInfo.declarations.push({ property: "rotate", value: 0 });
235+
break;
236+
}
237+
}
238+
return array;
239+
}
240+
}

‎nativescript-angular/application.ts‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ import {Observable} from "rxjs";
3535

3636
export type ProviderArray = Array<Type | Provider | any[]>;
3737

38-
import {defaultPageProvider, defaultDeviceProvider} from "./platform-providers";
38+
import {defaultPageProvider, defaultDeviceProvider,defaultAnimationDriverProvider} from "./platform-providers";
3939

4040
import * as nativescriptIntl from "nativescript-intl";
4141
global.Intl = nativescriptIntl;
@@ -97,6 +97,7 @@ export function bootstrap(appComponentType: any,
9797

9898
defaultPageProvider,
9999
defaultDeviceProvider,
100+
defaultAnimationDriverProvider,
100101
NativeScriptRootRenderer,
101102
provide(RootRenderer, { useClass: NativeScriptRootRenderer }),
102103
NativeScriptRenderer,

‎nativescript-angular/platform-providers.ts‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@ import {topmost} from 'ui/frame';
22
import {Page} from 'ui/page';
33
import {provide, Provider, OpaqueToken} from '@angular/core/src/di';
44
import {Device, ScreenMetrics, device, screen} from "platform";
5+
import {NativeScriptAnimationDriver} from './animation-driver';
56

67
export const APP_ROOT_VIEW = new OpaqueToken('App Root View');
78
export const DEVICE = new OpaqueToken('platfrom device');
9+
export const ANIMATION_DRIVER = new OpaqueToken('animation driver');
810

911
export const defaultPageProvider = provide(Page, { useFactory: getDefaultPage });
1012

@@ -19,3 +21,4 @@ export function getDefaultPage(): Page {
1921

2022
export const defaultDeviceProvider = provide(DEVICE, { useValue: device });
2123

24+
export const defaultAnimationDriverProvider = provide(ANIMATION_DRIVER, { useClass: NativeScriptAnimationDriver });

‎nativescript-angular/renderer.ts‎

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ import {
88
import { AnimationKeyframe } from '@angular/core/src/animation/animation_keyframe';
99
import { AnimationPlayer } from '@angular/core/src/animation/animation_player';
1010
import { AnimationStyles } from '@angular/core/src/animation/animation_styles';
11-
import {APP_ROOT_VIEW, DEVICE} from "./platform-providers";
11+
import { AnimationDriver } from '@angular/core/src/animation/animation_driver';
12+
import {APP_ROOT_VIEW, DEVICE, ANIMATION_DRIVER} from "./platform-providers";
1213
import {isBlank} from '@angular/core/src/facade/lang';
1314
import {CONTENT_ATTR} from '@angular/platform-browser/src/dom/dom_renderer';
1415
import {View} from "ui/core/view";
@@ -24,10 +25,12 @@ import { Device } from "platform";
2425
export class NativeScriptRootRenderer implements RootRenderer {
2526
private _rootView: View = null;
2627
private _viewUtil: ViewUtil;
28+
private _animationDriver: AnimationDriver;
2729

28-
constructor( @Optional() @Inject(APP_ROOT_VIEW) rootView: View, @Inject(DEVICE) device: Device) {
30+
constructor( @Optional() @Inject(APP_ROOT_VIEW) rootView: View, @Inject(DEVICE) device: Device, @Inject(ANIMATION_DRIVER)animationDriver) {
2931
this._rootView = rootView;
3032
this._viewUtil = new ViewUtil(device);
33+
this._animationDriver = animationDriver;
3134
}
3235

3336
private _registeredComponents: Map<string, NativeScriptRenderer> = new Map<string, NativeScriptRenderer>();
@@ -50,7 +53,7 @@ export class NativeScriptRootRenderer implements RootRenderer {
5053
renderComponent(componentProto: RenderComponentType): Renderer {
5154
var renderer = this._registeredComponents.get(componentProto.id);
5255
if (isBlank(renderer)) {
53-
renderer = new NativeScriptRenderer(this, componentProto);
56+
renderer = new NativeScriptRenderer(this, componentProto,this._animationDriver);
5457
this._registeredComponents.set(componentProto.id, renderer);
5558
}
5659
return renderer;
@@ -67,7 +70,7 @@ export class NativeScriptRenderer extends Renderer {
6770
return this.rootRenderer.viewUtil;
6871
}
6972

70-
constructor(private _rootRenderer: NativeScriptRootRenderer, private componentProto: RenderComponentType) {
73+
constructor(private _rootRenderer: NativeScriptRootRenderer, private componentProto: RenderComponentType,privateanimationDriver: AnimationDriver) {
7174
super();
7275
this.rootRenderer = _rootRenderer;
7376
let page = this.rootRenderer.page;
@@ -121,7 +124,6 @@ export class NativeScriptRenderer extends Renderer {
121124
viewRootNodes.forEach((node, index) => {
122125
const childIndex = insertPosition + index + 1;
123126
this.viewUtil.insertChild(parent, node, childIndex);
124-
this.animateNodeEnter(node);
125127
});
126128
}
127129

@@ -130,16 +132,9 @@ export class NativeScriptRenderer extends Renderer {
130132
for (var i = 0; i < viewRootNodes.length; i++) {
131133
var node = viewRootNodes[i];
132134
this.viewUtil.removeChild(<NgView>node.parent, node);
133-
this.animateNodeLeave(node);
134135
}
135136
}
136137

137-
animateNodeEnter(node: NgView) {
138-
}
139-
140-
animateNodeLeave(node: NgView) {
141-
}
142-
143138
public destroyView(hostElement: NgView, viewAllNodes: NgView[]) {
144139
traceLog("NativeScriptRenderer.destroyView");
145140
// Seems to be called on component dispose only (router outlet)
@@ -231,6 +226,7 @@ export class NativeScriptRenderer extends Renderer {
231226
}
232227

233228
public animate(element: any, startingStyles: AnimationStyles, keyframes: AnimationKeyframe[], duration: number, delay: number, easing: string): AnimationPlayer {
234-
throw new Error("NativeScriptRenderer.animate() - Not implemented");
229+
let player = this.animationDriver.animate(element, startingStyles, keyframes, duration, delay, easing);
230+
return player;
235231
}
236232
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /