mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-08-18 22:01:42 +08:00
Merge pull request #3596 from NativeScript/cankov/modules30-qsf
Animation properties and some backward compatability with the QSF
This commit is contained in:
58
apps/app/gallery-app/animations/css-keyframes.css
Normal file
58
apps/app/gallery-app/animations/css-keyframes.css
Normal file
@ -0,0 +1,58 @@
|
||||
@keyframes intro {
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform: translate(-100, 0);
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
transform: translate(0, 0);
|
||||
}
|
||||
}
|
||||
@keyframes outro {
|
||||
0% {
|
||||
opacity: 1;
|
||||
transform: translate(0, 0);
|
||||
}
|
||||
100% {
|
||||
opacity: 0;
|
||||
transform: translate(-100, 0);
|
||||
}
|
||||
}
|
||||
|
||||
.intro {
|
||||
animation-name: intro;
|
||||
animation-duration: 3.0;
|
||||
animation-fill-mode: forwards;
|
||||
animation-iteration-count: 1;
|
||||
animation-timing-function: cubic-bezier(0.25, 0.1, 0.25, 1);
|
||||
}
|
||||
.outro {
|
||||
animation-name: outro;
|
||||
animation-duration: 3.0;
|
||||
animation-fill-mode: forwards;
|
||||
animation-iteration-count: 1;
|
||||
animation-timing-function: cubic-bezier(0.25, 0.1, 0.25, 1);
|
||||
}
|
||||
|
||||
.gone {
|
||||
opacity: 0;
|
||||
transform: translate(-100, 0);
|
||||
}
|
||||
|
||||
@keyframes play {
|
||||
0% { transform: translate(0, 0); }
|
||||
33% { transform: translate(100, 0); }
|
||||
66% { transform: translate(100, 100); }
|
||||
100% { transform: translate(0, 100); }
|
||||
}
|
||||
|
||||
.idle {
|
||||
transform: translate(0, 0);
|
||||
}
|
||||
.play {
|
||||
animation-name: play;
|
||||
animation-duration: 3.0;
|
||||
animation-fill-mode: forwards;
|
||||
animation-iteration-count: 1;
|
||||
animation-timing-function: cubic-bezier(0.25, 0.1, 0.25, 1);
|
||||
}
|
13
apps/app/gallery-app/animations/css-keyframes.ts
Normal file
13
apps/app/gallery-app/animations/css-keyframes.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import { View, EventData } from "ui/core/view";
|
||||
|
||||
export function setClass(args: EventData) {
|
||||
const btn = (<View & { tag: any }>args.object);
|
||||
const img = btn.page.getViewById<View>("img");
|
||||
img.className = btn.tag;
|
||||
}
|
||||
|
||||
export function setImg2Class(args: EventData) {
|
||||
const btn = (<View & { tag: any }>args.object);
|
||||
const img2 = btn.page.getViewById<View>("img2");
|
||||
img2.className = btn.tag;
|
||||
}
|
18
apps/app/gallery-app/animations/css-keyframes.xml
Normal file
18
apps/app/gallery-app/animations/css-keyframes.xml
Normal file
@ -0,0 +1,18 @@
|
||||
<Page xmlns="http://schemas.nativescript.org/tns.xsd" loaded="pageLoaded" id="mainPage">
|
||||
<StackLayout orientation="vertical">
|
||||
<Button text="class: gone" tag="gone" tap="setClass" />
|
||||
<Button text="class: intro" tag="intro" tap="setClass" />
|
||||
<Button text="class: outro" tag="outro" tap="setClass" />
|
||||
<Button text="clear class" tag="none" tap="setClass" />
|
||||
|
||||
<GridLayout horizontalAlignment="center" verticalAlignment="middle" backgroundColor="blue" width="150" height="50">
|
||||
<GridLayout id="img" class="gone" backgroundColor="green" width="50" height="50" horizontalAlignment="right" />
|
||||
</GridLayout>
|
||||
|
||||
<Button text="class: idle" tag="idle" tap="setImg2Class" />
|
||||
<Button text="class: play" tag="play" tap="setImg2Class" />
|
||||
<GridLayout horizontalAlignment="center" verticalAlignment="middle" backgroundColor="gray" width="150" height="150">
|
||||
<GridLayout id="img2" class="idle" backgroundColor="green" width="50" height="50" horizontalAlignment="left" verticalAlignment="top" />
|
||||
</GridLayout>
|
||||
</StackLayout>
|
||||
</Page>
|
@ -4,12 +4,47 @@ import * as buttonModule from "ui/button";
|
||||
import * as abs from "ui/layouts/absolute-layout";
|
||||
import * as animationModule from "ui/animation";
|
||||
import * as colorModule from "color";
|
||||
import * as model from "./model";
|
||||
import * as enums from "ui/enums";
|
||||
import * as frame from "ui/frame";
|
||||
import * as trace from "trace";
|
||||
|
||||
var vm = new model.ViewModel();
|
||||
export class ViewModel extends observable.Observable {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this._duration = 3000;
|
||||
this._iterations = 1;
|
||||
}
|
||||
|
||||
private _playSequentially: boolean;
|
||||
get playSequentially(): boolean {
|
||||
return this._playSequentially;
|
||||
}
|
||||
set playSequentially(value: boolean) {
|
||||
this._playSequentially = value;
|
||||
this.notify({ object: this, eventName: observable.Observable.propertyChangeEvent, propertyName: "playSequentially", value: value });
|
||||
}
|
||||
|
||||
private _duration: number;
|
||||
get duration(): number {
|
||||
return this._duration;
|
||||
}
|
||||
set duration(value: number) {
|
||||
this._duration = value;
|
||||
this.notify({ object: this, eventName: observable.Observable.propertyChangeEvent, propertyName: "duration", value: value });
|
||||
}
|
||||
|
||||
private _iterations: number;
|
||||
get iterations(): number {
|
||||
return this._iterations;
|
||||
}
|
||||
set iterations(value: number) {
|
||||
this._iterations = value;
|
||||
this.notify({ object: this, eventName: observable.Observable.propertyChangeEvent, propertyName: "iterations", value: value });
|
||||
}
|
||||
}
|
||||
|
||||
var vm = new ViewModel();
|
||||
|
||||
var page: pages.Page;
|
||||
var panel: abs.AbsoluteLayout;
|
||||
@ -27,8 +62,8 @@ export function pageLoaded(args: observable.EventData) {
|
||||
button2 = page.getViewById<buttonModule.Button>("button2");
|
||||
button3 = page.getViewById<buttonModule.Button>("button3");
|
||||
|
||||
trace.enable();
|
||||
trace.addCategories(trace.categories.concat(trace.categories.Animation));
|
||||
// trace.enable();
|
||||
// trace.addCategories(trace.categories.concat(trace.categories.Animation));
|
||||
}
|
||||
|
||||
export function onSlideOut(args: observable.EventData) {
|
@ -18,7 +18,6 @@
|
||||
<Button text="In" tap="onSlideIn" width="40" marginLeft="5" marginRight="5" />
|
||||
<Button text="Single" tap="onSingle" width="70" marginLeft="5" marginRight="5" />
|
||||
<Button text="Cancel" tap="onCancel" width="70" marginLeft="5" marginRight="5" />
|
||||
<Button text="Opacity" tap="onOpacity" width="70" marginLeft="5" marginRight="5" />
|
||||
</StackLayout>
|
||||
|
||||
<StackLayout orientation="horizontal" marginTop="5" marginBottom="5" horizontalAlignment="center" paddingLeft="5" paddingRight="5">>
|
@ -1,37 +0,0 @@
|
||||
import observable = require("data/observable");
|
||||
|
||||
export class ViewModel extends observable.Observable {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this._duration = 3000;
|
||||
this._iterations = 1;
|
||||
}
|
||||
|
||||
private _playSequentially: boolean;
|
||||
get playSequentially(): boolean {
|
||||
return this._playSequentially;
|
||||
}
|
||||
set playSequentially(value: boolean) {
|
||||
this._playSequentially = value;
|
||||
this.notify({ object: this, eventName: observable.Observable.propertyChangeEvent, propertyName: "playSequentially", value: value });
|
||||
}
|
||||
|
||||
private _duration: number;
|
||||
get duration(): number {
|
||||
return this._duration;
|
||||
}
|
||||
set duration(value: number) {
|
||||
this._duration = value;
|
||||
this.notify({ object: this, eventName: observable.Observable.propertyChangeEvent, propertyName: "duration", value: value });
|
||||
}
|
||||
|
||||
private _iterations: number;
|
||||
get iterations(): number {
|
||||
return this._iterations;
|
||||
}
|
||||
set iterations(value: number) {
|
||||
this._iterations = value;
|
||||
this.notify({ object: this, eventName: observable.Observable.propertyChangeEvent, propertyName: "iterations", value: value });
|
||||
}
|
||||
}
|
@ -43,8 +43,9 @@
|
||||
|
||||
<Label class="title" text="Animations" />
|
||||
<StackLayout>
|
||||
<Button tag="animations/configurable" text="configurable" tap="itemTap" />
|
||||
<Button tag="animations/opacity" text="opacity" tap="itemTap" />
|
||||
<Button tag="animations/js-configurable" text="js-configurable" tap="itemTap" />
|
||||
<Button tag="animations/js-opacity" text="js-opacity" tap="itemTap" />
|
||||
<Button tag="animations/css-keyframes" text="css-keyframes" tap="itemTap" />
|
||||
</StackLayout>
|
||||
</StackLayout>
|
||||
</ScrollView>
|
||||
|
@ -3,7 +3,7 @@ import {
|
||||
AnimationBase, Properties, PropertyAnimation, CubicBezierAnimationCurve, AnimationPromise,
|
||||
opacityProperty, backgroundColorProperty, rotateProperty,
|
||||
translateXProperty, translateYProperty,
|
||||
scaleXProperty, scaleYProperty, Color, traceWrite, traceEnabled, traceCategories
|
||||
scaleXProperty, scaleYProperty, Color, traceWrite, traceEnabled, traceCategories, unsetValue
|
||||
} from "./animation-common";
|
||||
|
||||
import { CacheLayerType, layout } from "utils/utils";
|
||||
@ -12,7 +12,7 @@ import lazy from "utils/lazy";
|
||||
export * from "./animation-common";
|
||||
|
||||
interface AnimationDefinitionInternal extends AnimationDefinition {
|
||||
valueSource?: number;
|
||||
valueSource?: "animation" | "keyframe";
|
||||
}
|
||||
|
||||
let argbEvaluator: android.animation.ArgbEvaluator;
|
||||
@ -88,7 +88,7 @@ export class Animation extends AnimationBase {
|
||||
private _animators: Array<android.animation.Animator>;
|
||||
private _propertyUpdateCallbacks: Array<Function>;
|
||||
private _propertyResetCallbacks: Array<Function>;
|
||||
private _valueSource: number;
|
||||
private _valueSource: "animation" | "keyframe";
|
||||
|
||||
constructor(animationDefinitions: Array<AnimationDefinitionInternal>, playSequentially?: boolean) {
|
||||
super(animationDefinitions, playSequentially);
|
||||
@ -243,7 +243,7 @@ export class Animation extends AnimationBase {
|
||||
}
|
||||
}
|
||||
|
||||
// let valueSource = this._valueSource !== undefined ? this._valueSource : dependencyObservable.ValueSource.Local;
|
||||
let setLocal = this._valueSource === "animation";
|
||||
|
||||
switch (propertyAnimation.property) {
|
||||
case Properties.opacity:
|
||||
@ -251,10 +251,17 @@ export class Animation extends AnimationBase {
|
||||
nativeArray = Array.create("float", 1);
|
||||
nativeArray[0] = propertyAnimation.value;
|
||||
propertyUpdateCallbacks.push(checkAnimation(() => {
|
||||
propertyAnimation.target.style[opacityProperty.cssName] = propertyAnimation.value;
|
||||
propertyAnimation.target.style[setLocal ? opacityProperty.name : opacityProperty.keyframe] = propertyAnimation.value;
|
||||
}));
|
||||
propertyResetCallbacks.push(checkAnimation(() => {
|
||||
propertyAnimation.target.style[opacityProperty.cssName] = originalValue1;
|
||||
if (setLocal) {
|
||||
propertyAnimation.target.style[opacityProperty.name] = originalValue1;
|
||||
} else {
|
||||
propertyAnimation.target.style[opacityProperty.keyframe] = originalValue1;
|
||||
}
|
||||
if (propertyAnimation.target.nativeView) {
|
||||
propertyAnimation.target[opacityProperty.native] = propertyAnimation.target.style.opacity;
|
||||
}
|
||||
}));
|
||||
animators.push(android.animation.ObjectAnimator.ofFloat(nativeView, "alpha", nativeArray));
|
||||
break;
|
||||
@ -274,10 +281,17 @@ export class Animation extends AnimationBase {
|
||||
}));
|
||||
|
||||
propertyUpdateCallbacks.push(checkAnimation(() => {
|
||||
propertyAnimation.target.style[backgroundColorProperty.cssName] = propertyAnimation.value;
|
||||
propertyAnimation.target.style[setLocal ? backgroundColorProperty.name : backgroundColorProperty.keyframe] = propertyAnimation.value;
|
||||
}));
|
||||
propertyResetCallbacks.push(checkAnimation(() => {
|
||||
propertyAnimation.target.style[backgroundColorProperty.cssName] = originalValue1;
|
||||
if (setLocal) {
|
||||
propertyAnimation.target.style[backgroundColorProperty.name] = originalValue1;
|
||||
} else {
|
||||
propertyAnimation.target.style[backgroundColorProperty.keyframe] = originalValue1;
|
||||
if (propertyAnimation.target.nativeView) {
|
||||
propertyAnimation.target[backgroundColorProperty.native] = propertyAnimation.target.style.backgroundColor;
|
||||
}
|
||||
}
|
||||
}));
|
||||
animators.push(animator);
|
||||
break;
|
||||
@ -295,17 +309,26 @@ export class Animation extends AnimationBase {
|
||||
xyObjectAnimators[1] = android.animation.ObjectAnimator.ofFloat(nativeView, "translationY", nativeArray);
|
||||
xyObjectAnimators[1].setRepeatCount(Animation._getAndroidRepeatCount(propertyAnimation.iterations));
|
||||
|
||||
originalValue1 = nativeView.getTranslationX();
|
||||
originalValue2 = nativeView.getTranslationY();
|
||||
originalValue1 = nativeView.getTranslationX() / density;
|
||||
originalValue2 = nativeView.getTranslationY() / density;
|
||||
|
||||
propertyUpdateCallbacks.push(checkAnimation(() => {
|
||||
propertyAnimation.target.style[translateXProperty.cssName] = propertyAnimation.value.x;
|
||||
propertyAnimation.target.style[translateYProperty.cssName] = propertyAnimation.value.y;
|
||||
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(() => {
|
||||
propertyAnimation.target.style[translateXProperty.cssName] = originalValue1;
|
||||
propertyAnimation.target.style[translateYProperty.cssName] = originalValue2;
|
||||
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.nativeView) {
|
||||
propertyAnimation.target[translateXProperty.native] = propertyAnimation.target.style.translateX;
|
||||
propertyAnimation.target[translateYProperty.native] = propertyAnimation.target.style.translateY;
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
animatorSet = new android.animation.AnimatorSet();
|
||||
@ -331,13 +354,22 @@ export class Animation extends AnimationBase {
|
||||
originalValue2 = nativeView.getScaleY();
|
||||
|
||||
propertyUpdateCallbacks.push(checkAnimation(() => {
|
||||
propertyAnimation.target.style[scaleXProperty.cssName] = propertyAnimation.value.x;
|
||||
propertyAnimation.target.style[scaleYProperty.cssName] = propertyAnimation.value.y;
|
||||
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(() => {
|
||||
propertyAnimation.target.style[scaleXProperty.cssName] = originalValue1;
|
||||
propertyAnimation.target.style[scaleYProperty.cssName] = originalValue2;
|
||||
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.nativeView) {
|
||||
propertyAnimation.target[scaleXProperty.native] = propertyAnimation.target.style.scaleX;
|
||||
propertyAnimation.target[scaleYProperty.native] = propertyAnimation.target.style.scaleY;
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
animatorSet = new android.animation.AnimatorSet();
|
||||
@ -351,10 +383,17 @@ export class Animation extends AnimationBase {
|
||||
nativeArray = Array.create("float", 1);
|
||||
nativeArray[0] = propertyAnimation.value;
|
||||
propertyUpdateCallbacks.push(checkAnimation(() => {
|
||||
propertyAnimation.target.style[rotateProperty.cssName] = propertyAnimation.value;
|
||||
propertyAnimation.target.style[setLocal ? rotateProperty.name : rotateProperty.keyframe] = propertyAnimation.value;
|
||||
}));
|
||||
propertyResetCallbacks.push(checkAnimation(() => {
|
||||
propertyAnimation.target.style[rotateProperty.cssName] = originalValue1;
|
||||
if (setLocal) {
|
||||
propertyAnimation.target.style[rotateProperty.name] = originalValue1;
|
||||
} else {
|
||||
propertyAnimation.target.style[rotateProperty.keyframe] = originalValue1;
|
||||
if (propertyAnimation.target.nativeView) {
|
||||
propertyAnimation.target[rotateProperty.native] = propertyAnimation.target.style.rotate;
|
||||
}
|
||||
}
|
||||
}));
|
||||
animators.push(android.animation.ObjectAnimator.ofFloat(nativeView, "rotation", nativeArray));
|
||||
break;
|
||||
|
@ -2,7 +2,7 @@ import { AnimationDefinition } from "ui/animation";
|
||||
import {
|
||||
AnimationBase, Properties, PropertyAnimation, CubicBezierAnimationCurve, AnimationPromise, View, opacityProperty, backgroundColorProperty, rotateProperty,
|
||||
translateXProperty, translateYProperty,
|
||||
scaleXProperty, scaleYProperty, traceEnabled, traceWrite, traceCategories
|
||||
scaleXProperty, scaleYProperty, traceEnabled, traceWrite, traceCategories, Length
|
||||
} from "./animation-common";
|
||||
|
||||
import { ios } from "utils/utils";
|
||||
@ -33,7 +33,7 @@ interface PropertyAnimationInfo extends PropertyAnimation {
|
||||
}
|
||||
|
||||
interface AnimationDefinitionInternal extends AnimationDefinition {
|
||||
valueSource?: number;
|
||||
valueSource?: "animation" | "keyframe";
|
||||
}
|
||||
|
||||
interface IOSView extends View {
|
||||
@ -51,9 +51,9 @@ class AnimationDelegateImpl extends NSObject implements CAAnimationDelegate {
|
||||
|
||||
private _finishedCallback: Function;
|
||||
private _propertyAnimation: PropertyAnimationInfo;
|
||||
private _valueSource: number;
|
||||
private _valueSource: "animation" | "keyframe";
|
||||
|
||||
public static initWithFinishedCallback(finishedCallback: Function, propertyAnimation: PropertyAnimationInfo, valueSource: number): AnimationDelegateImpl {
|
||||
public static initWithFinishedCallback(finishedCallback: Function, propertyAnimation: PropertyAnimationInfo, valueSource: "animation" | "keyframe"): AnimationDelegateImpl {
|
||||
let delegate = <AnimationDelegateImpl>AnimationDelegateImpl.new();
|
||||
delegate._finishedCallback = finishedCallback;
|
||||
delegate._propertyAnimation = propertyAnimation;
|
||||
@ -63,40 +63,39 @@ class AnimationDelegateImpl extends NSObject implements CAAnimationDelegate {
|
||||
|
||||
animationDidStart(anim: CAAnimation): void {
|
||||
let value = this._propertyAnimation.value;
|
||||
// let valueSource = this._valueSource || dependencyObservable.ValueSource.Local;
|
||||
let setLocal = true;
|
||||
let setLocal = this._valueSource === "animation";
|
||||
let targetStyle = this._propertyAnimation.target.style;
|
||||
|
||||
(<IOSView>this._propertyAnimation.target)._suspendPresentationLayerUpdates();
|
||||
|
||||
switch (this._propertyAnimation.property) {
|
||||
case Properties.backgroundColor:
|
||||
targetStyle[setLocal ? backgroundColorProperty.name : backgroundColorProperty.cssName] = value;
|
||||
targetStyle[setLocal ? backgroundColorProperty.name : backgroundColorProperty.keyframe] = value;
|
||||
break;
|
||||
case Properties.opacity:
|
||||
targetStyle[setLocal ? opacityProperty.name : opacityProperty.cssName] = value;
|
||||
targetStyle[setLocal ? opacityProperty.name : opacityProperty.keyframe] = value;
|
||||
break;
|
||||
case Properties.rotate:
|
||||
targetStyle[setLocal ? rotateProperty.name : rotateProperty.cssName] = value;
|
||||
targetStyle[setLocal ? rotateProperty.name : rotateProperty.keyframe] = value;
|
||||
break;
|
||||
case Properties.translate:
|
||||
targetStyle[setLocal ? translateXProperty.name : translateXProperty.cssName] = value;
|
||||
targetStyle[setLocal ? translateYProperty.name : translateYProperty.cssName] = value;
|
||||
targetStyle[setLocal ? translateXProperty.name : translateXProperty.keyframe] = value;
|
||||
targetStyle[setLocal ? translateYProperty.name : translateYProperty.keyframe] = value;
|
||||
break;
|
||||
case Properties.scale:
|
||||
targetStyle[setLocal ? scaleXProperty.name : scaleXProperty.cssName] = value.x === 0 ? 0.001 : value.x;
|
||||
targetStyle[setLocal ? scaleYProperty.name : scaleYProperty.cssName] = value.y === 0 ? 0.001 : value.y;
|
||||
targetStyle[setLocal ? scaleXProperty.name : scaleXProperty.keyframe] = value.x === 0 ? 0.001 : value.x;
|
||||
targetStyle[setLocal ? scaleYProperty.name : scaleYProperty.keyframe] = value.y === 0 ? 0.001 : value.y;
|
||||
break;
|
||||
case _transform:
|
||||
if (value[Properties.translate] !== undefined) {
|
||||
targetStyle[setLocal ? translateXProperty.name : translateXProperty.cssName] = value[Properties.translate].x;
|
||||
targetStyle[setLocal ? translateYProperty.name : translateYProperty.cssName] = value[Properties.translate].y;
|
||||
targetStyle[setLocal ? translateXProperty.name : translateXProperty.keyframe] = value[Properties.translate].x;
|
||||
targetStyle[setLocal ? translateYProperty.name : translateYProperty.keyframe] = value[Properties.translate].y;
|
||||
}
|
||||
if (value[Properties.scale] !== undefined) {
|
||||
let x = value[Properties.scale].x;
|
||||
let y = value[Properties.scale].y;
|
||||
targetStyle[setLocal ? scaleXProperty.name : scaleXProperty.cssName] = x === 0 ? 0.001 : x;
|
||||
targetStyle[setLocal ? scaleYProperty.name : scaleYProperty.cssName] = y === 0 ? 0.001 : y;
|
||||
targetStyle[setLocal ? scaleXProperty.name : scaleXProperty.keyframe] = x === 0 ? 0.001 : x;
|
||||
targetStyle[setLocal ? scaleYProperty.name : scaleYProperty.keyframe] = y === 0 ? 0.001 : y;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -147,7 +146,7 @@ export class Animation extends AnimationBase {
|
||||
private _finishedAnimations: number;
|
||||
private _cancelledAnimations: number;
|
||||
private _mergedPropertyAnimations: Array<PropertyAnimationInfo>;
|
||||
private _valueSource: number;
|
||||
private _valueSource: "animation" | "keyframe";
|
||||
|
||||
constructor(animationDefinitions: Array<AnimationDefinitionInternal>, playSequentially?: boolean) {
|
||||
super(animationDefinitions, playSequentially);
|
||||
@ -233,7 +232,7 @@ export class Animation extends AnimationBase {
|
||||
return _resolveAnimationCurve(curve);
|
||||
}
|
||||
|
||||
private static _createiOSAnimationFunction(propertyAnimations: Array<PropertyAnimation>, index: number, playSequentially: boolean, valueSource: number, finishedCallback: (cancelled?: boolean) => void): Function {
|
||||
private static _createiOSAnimationFunction(propertyAnimations: Array<PropertyAnimation>, index: number, playSequentially: boolean, valueSource: "animation" | "keyframe", finishedCallback: (cancelled?: boolean) => void): Function {
|
||||
return (cancelled?: boolean) => {
|
||||
|
||||
if (cancelled && finishedCallback) {
|
||||
@ -256,7 +255,7 @@ export class Animation extends AnimationBase {
|
||||
}
|
||||
}
|
||||
|
||||
private static _getNativeAnimationArguments(animation: PropertyAnimationInfo, valueSource: number): AnimationInfo {
|
||||
private static _getNativeAnimationArguments(animation: PropertyAnimationInfo, valueSource: "animation" | "keyframe"): AnimationInfo {
|
||||
|
||||
let nativeView = <UIView>animation.target._nativeView;
|
||||
let propertyNameToAnimate = animation.property;
|
||||
@ -266,16 +265,13 @@ export class Animation extends AnimationBase {
|
||||
let tempRotate = (animation.target.rotate || 0) * Math.PI / 180;
|
||||
let abs;
|
||||
|
||||
let setLocal = true;
|
||||
// if (valueSource === undefined) {
|
||||
// valueSource = dependencyObservable.ValueSource.Local;
|
||||
// }
|
||||
let setLocal = valueSource === "animation";
|
||||
|
||||
switch (animation.property) {
|
||||
case Properties.backgroundColor:
|
||||
animation._originalValue = animation.target.backgroundColor;
|
||||
animation._propertyResetCallback = (value, valueSource) => {
|
||||
animation.target.style[setLocal ? backgroundColorProperty.name : backgroundColorProperty.cssName] = value;
|
||||
animation.target.style[setLocal ? backgroundColorProperty.name : backgroundColorProperty.keyframe] = value;
|
||||
};
|
||||
originalValue = nativeView.layer.backgroundColor;
|
||||
if (nativeView instanceof UILabel) {
|
||||
@ -286,14 +282,14 @@ export class Animation extends AnimationBase {
|
||||
case Properties.opacity:
|
||||
animation._originalValue = animation.target.opacity;
|
||||
animation._propertyResetCallback = (value, valueSource) => {
|
||||
animation.target.style[setLocal ? opacityProperty.name : opacityProperty.cssName] = value;
|
||||
animation.target.style[setLocal ? opacityProperty.name : opacityProperty.keyframe] = value;
|
||||
};
|
||||
originalValue = nativeView.layer.opacity;
|
||||
break;
|
||||
case Properties.rotate:
|
||||
animation._originalValue = animation.target.rotate !== undefined ? animation.target.rotate : 0;
|
||||
animation._propertyResetCallback = (value, valueSource) => {
|
||||
animation.target.style[setLocal ? rotateProperty.name : rotateProperty.cssName] = value;
|
||||
animation.target.style[setLocal ? rotateProperty.name : rotateProperty.keyframe] = value;
|
||||
};
|
||||
propertyNameToAnimate = "transform.rotation";
|
||||
originalValue = nativeView.layer.valueForKeyPath("transform.rotation");
|
||||
@ -309,8 +305,8 @@ export class Animation extends AnimationBase {
|
||||
case Properties.translate:
|
||||
animation._originalValue = { x: animation.target.translateX, y: animation.target.translateY };
|
||||
animation._propertyResetCallback = (value, valueSource) => {
|
||||
animation.target.style[setLocal ? translateXProperty.name : translateXProperty.cssName] = value.x;
|
||||
animation.target.style[setLocal ? translateYProperty.name : translateYProperty.cssName] = value.y;
|
||||
animation.target.style[setLocal ? translateXProperty.name : translateXProperty.keyframe] = value.x;
|
||||
animation.target.style[setLocal ? translateYProperty.name : translateYProperty.keyframe] = value.y;
|
||||
};
|
||||
propertyNameToAnimate = "transform";
|
||||
originalValue = NSValue.valueWithCATransform3D(nativeView.layer.transform);
|
||||
@ -325,8 +321,8 @@ export class Animation extends AnimationBase {
|
||||
}
|
||||
animation._originalValue = { x: animation.target.scaleX, y: animation.target.scaleY };
|
||||
animation._propertyResetCallback = (value, valueSource) => {
|
||||
animation.target.style[setLocal ? scaleXProperty.name : scaleXProperty.cssName] = value.x;
|
||||
animation.target.style[setLocal ? scaleYProperty.name : scaleYProperty.cssName] = value.y;
|
||||
animation.target.style[setLocal ? scaleXProperty.name : scaleXProperty.keyframe] = value.x;
|
||||
animation.target.style[setLocal ? scaleYProperty.name : scaleYProperty.keyframe] = value.y;
|
||||
};
|
||||
propertyNameToAnimate = "transform";
|
||||
originalValue = NSValue.valueWithCATransform3D(nativeView.layer.transform);
|
||||
@ -339,10 +335,10 @@ export class Animation extends AnimationBase {
|
||||
xt: animation.target.translateX, yt: animation.target.translateY
|
||||
};
|
||||
animation._propertyResetCallback = (value, valueSource) => {
|
||||
animation.target.style[setLocal ? translateXProperty.name : translateXProperty.cssName] = value.xt;
|
||||
animation.target.style[setLocal ? translateYProperty.name : translateYProperty.cssName] = value.yt;
|
||||
animation.target.style[setLocal ? scaleXProperty.name : scaleXProperty.cssName] = value.xs;
|
||||
animation.target.style[setLocal ? scaleYProperty.name : scaleYProperty.cssName] = value.ys;
|
||||
animation.target.style[setLocal ? translateXProperty.name : translateXProperty.keyframe] = value.xt;
|
||||
animation.target.style[setLocal ? translateYProperty.name : translateYProperty.keyframe] = value.yt;
|
||||
animation.target.style[setLocal ? scaleXProperty.name : scaleXProperty.keyframe] = value.xs;
|
||||
animation.target.style[setLocal ? scaleYProperty.name : scaleYProperty.keyframe] = value.ys;
|
||||
};
|
||||
propertyNameToAnimate = "transform";
|
||||
value = NSValue.valueWithCATransform3D(Animation._createNativeAffineTransform(animation));
|
||||
@ -381,7 +377,7 @@ export class Animation extends AnimationBase {
|
||||
};
|
||||
}
|
||||
|
||||
private static _createNativeAnimation(propertyAnimations: Array<PropertyAnimation>, index: number, playSequentially: boolean, args: AnimationInfo, animation: PropertyAnimation, valueSource: number, finishedCallback: (cancelled?: boolean) => void) {
|
||||
private static _createNativeAnimation(propertyAnimations: Array<PropertyAnimation>, index: number, playSequentially: boolean, args: AnimationInfo, animation: PropertyAnimation, valueSource: "animation" | "keyframe", finishedCallback: (cancelled?: boolean) => void) {
|
||||
|
||||
let nativeView = <UIView>animation.target._nativeView;
|
||||
let nativeAnimation = CABasicAnimation.animationWithKeyPath(args.propertyNameToAnimate);
|
||||
@ -415,7 +411,7 @@ export class Animation extends AnimationBase {
|
||||
}
|
||||
}
|
||||
|
||||
private static _createNativeSpringAnimation(propertyAnimations: Array<PropertyAnimationInfo>, index: number, playSequentially: boolean, args: AnimationInfo, animation: PropertyAnimationInfo, valueSource: number, finishedCallback: (cancelled?: boolean) => void) {
|
||||
private static _createNativeSpringAnimation(propertyAnimations: Array<PropertyAnimationInfo>, index: number, playSequentially: boolean, args: AnimationInfo, animation: PropertyAnimationInfo, valueSource: "animation" | "keyframe", finishedCallback: (cancelled?: boolean) => void) {
|
||||
|
||||
let nativeView = <UIView>animation.target._nativeView;
|
||||
|
||||
@ -591,7 +587,7 @@ export class Animation extends AnimationBase {
|
||||
export function _getTransformMismatchErrorMessage(view: View): string {
|
||||
// Order is important: translate, rotate, scale
|
||||
let result: CGAffineTransform = CGAffineTransformIdentity;
|
||||
result = CGAffineTransformTranslate(result, view.translateX || 0, view.translateY || 0);
|
||||
result = CGAffineTransformTranslate(result, Length.toDevicePixels(view.translateX || 0, 0), Length.toDevicePixels(view.translateY || 0, 0));
|
||||
result = CGAffineTransformRotate(result, (view.rotate || 0) * Math.PI / 180);
|
||||
result = CGAffineTransformScale(result, view.scaleX || 1, view.scaleY || 1);
|
||||
let viewTransform = NSStringFromCGAffineTransform(result);
|
||||
|
@ -5,7 +5,18 @@ import {
|
||||
KeyframeAnimation as KeyframeAnimationDefinition
|
||||
} from "ui/animation/keyframe-animation";
|
||||
|
||||
import { View, unsetValue } from "ui/core/view";
|
||||
import {
|
||||
View,
|
||||
backgroundColorProperty,
|
||||
scaleXProperty,
|
||||
scaleYProperty,
|
||||
translateXProperty,
|
||||
translateYProperty,
|
||||
rotateProperty,
|
||||
opacityProperty,
|
||||
unsetValue,
|
||||
Color
|
||||
} from "ui/core/view";
|
||||
import { Animation } from "ui/animation";
|
||||
|
||||
export class KeyframeDeclaration implements KeyframeDeclarationDefinition {
|
||||
@ -30,8 +41,20 @@ export class KeyframeAnimationInfo implements KeyframeAnimationInfoDefinition {
|
||||
public keyframes: Array<KeyframeInfo>;
|
||||
}
|
||||
|
||||
interface Keyframe {
|
||||
backgroundColor?: Color;
|
||||
scale?: { x: number, y: number };
|
||||
translate?: { x: number, y: number };
|
||||
rotate?: number;
|
||||
opacity?: number;
|
||||
valueSource?: "keyframe" | "animation";
|
||||
duration?: number;
|
||||
curve?: any;
|
||||
forceLayer?: boolean;
|
||||
}
|
||||
|
||||
export class KeyframeAnimation implements KeyframeAnimationDefinition {
|
||||
public animations: Array<Object>;
|
||||
public animations: Array<Keyframe>;
|
||||
public delay: number = 0;
|
||||
public iterations: number = 1;
|
||||
|
||||
@ -43,7 +66,7 @@ export class KeyframeAnimation implements KeyframeAnimationDefinition {
|
||||
private _target: View;
|
||||
|
||||
public static keyframeAnimationFromInfo(info: KeyframeAnimationInfo) {
|
||||
let animations = new Array<Object>();
|
||||
let animations = new Array<Keyframe>();
|
||||
let length = info.keyframes.length;
|
||||
let startDuration = 0;
|
||||
if (info.isReverse) {
|
||||
@ -81,7 +104,7 @@ export class KeyframeAnimation implements KeyframeAnimationDefinition {
|
||||
}
|
||||
|
||||
private static parseKeyframe(info: KeyframeAnimationInfo, keyframe: KeyframeInfo, animations: Array<Object>, startDuration: number): number {
|
||||
let animation = {};
|
||||
let animation: Keyframe = {};
|
||||
for (let declaration of keyframe.declarations) {
|
||||
animation[declaration.property] = declaration.value;
|
||||
}
|
||||
@ -93,9 +116,10 @@ export class KeyframeAnimation implements KeyframeAnimationDefinition {
|
||||
duration = (info.duration * duration) - startDuration;
|
||||
startDuration += duration;
|
||||
}
|
||||
animation["duration"] = info.isReverse ? info.duration - duration : duration;
|
||||
animation["curve"] = keyframe.curve;
|
||||
animation["forceLayer"] = true;
|
||||
animation.duration = info.isReverse ? info.duration - duration : duration;
|
||||
animation.curve = keyframe.curve;
|
||||
animation.forceLayer = true;
|
||||
animation.valueSource = "keyframe";
|
||||
animations.push(animation);
|
||||
return startDuration;
|
||||
}
|
||||
@ -153,21 +177,21 @@ export class KeyframeAnimation implements KeyframeAnimationDefinition {
|
||||
let animation = this.animations[0];
|
||||
|
||||
if ("backgroundColor" in animation) {
|
||||
view.style[`css-background-color`] = animation["backgroundColor"];
|
||||
view.style[backgroundColorProperty.keyframe] = animation.backgroundColor;
|
||||
}
|
||||
if ("scale" in animation) {
|
||||
view.style["css-scaleX"] = animation["scale"].x;
|
||||
view.style["css-scaleY"] = animation["scale"].y;
|
||||
view.style[scaleXProperty.keyframe] = animation.scale.x;
|
||||
view.style[scaleYProperty.keyframe] = animation.scale.y;
|
||||
}
|
||||
if ("translate" in animation) {
|
||||
view.style["css-translateX"] = animation["translate"].x;
|
||||
view.style["css-translateY"] = animation["translate"].y;
|
||||
view.style[translateXProperty.keyframe] = animation.translate.x;
|
||||
view.style[translateYProperty.keyframe] = animation.translate.y;
|
||||
}
|
||||
if ("rotate" in animation) {
|
||||
view.style["css-rotate"] = animation["rotate"];
|
||||
view.style[rotateProperty.keyframe] = animation.rotate;
|
||||
}
|
||||
if ("opacity" in animation) {
|
||||
view.style["css-opacity"] = animation["opacity"];
|
||||
view.style[opacityProperty.keyframe] = animation.opacity;
|
||||
}
|
||||
|
||||
setTimeout(() => this.animate(view, 1, iterations), 1);
|
||||
@ -212,21 +236,21 @@ export class KeyframeAnimation implements KeyframeAnimationDefinition {
|
||||
|
||||
private _resetAnimationValues(view: View, animation: Object) {
|
||||
if ("backgroundColor" in animation) {
|
||||
view.style[`css-background-color`] = unsetValue;
|
||||
view.style[backgroundColorProperty.keyframe] = unsetValue;
|
||||
}
|
||||
if ("scale" in animation) {
|
||||
view.style["css-scaleX"] = animation["scale"].x;
|
||||
view.style["css-scaleY"] = animation["scale"].y;
|
||||
view.style[scaleXProperty.keyframe] = unsetValue;
|
||||
view.style[scaleYProperty.keyframe] = unsetValue;
|
||||
}
|
||||
if ("translate" in animation) {
|
||||
view.style["css-translateX"] = animation["translate"].x;
|
||||
view.style["css-translateY"] = animation["translate"].y;
|
||||
view.style[translateXProperty.keyframe] = unsetValue;
|
||||
view.style[translateYProperty.keyframe] = unsetValue;
|
||||
}
|
||||
if ("rotate" in animation) {
|
||||
view.style["css-rotate"] = animation["rotate"];
|
||||
view.style[rotateProperty.keyframe] = unsetValue;
|
||||
}
|
||||
if ("opacity" in animation) {
|
||||
view.style["css-opacity"] = animation["opacity"];
|
||||
view.style[opacityProperty.keyframe] = unsetValue;
|
||||
}
|
||||
}
|
||||
}
|
@ -9,6 +9,9 @@ export const unsetValue: any = new Object();
|
||||
|
||||
let symbolPropertyMap = {};
|
||||
let cssSymbolPropertyMap = {};
|
||||
|
||||
let cssSymbolResetMap = {};
|
||||
|
||||
let inheritableProperties = new Array<InheritedProperty<any, any>>();
|
||||
let inheritableCssProperties = new Array<InheritedCssProperty<any, any>>();
|
||||
|
||||
@ -35,7 +38,8 @@ const enum ValueSource {
|
||||
Default = 0,
|
||||
Inherited = 1,
|
||||
Css = 2,
|
||||
Local = 3
|
||||
Local = 3,
|
||||
Keyframe = 4
|
||||
}
|
||||
|
||||
export class Property<T extends ViewBase, U> implements TypedPropertyDescriptor<U>, definitions.Property<T, U> {
|
||||
@ -359,7 +363,7 @@ export class CssProperty<T extends Style, U> implements definitions.CssProperty<
|
||||
const name = options.name;
|
||||
this.name = name;
|
||||
|
||||
this.cssName = `css-${options.cssName}`;
|
||||
this.cssName = `css:${options.cssName}`;
|
||||
this.cssLocalName = options.cssName;
|
||||
|
||||
const key = Symbol(name + ":propertyKey");
|
||||
@ -541,6 +545,106 @@ export class CssProperty<T extends Style, U> implements definitions.CssProperty<
|
||||
}
|
||||
}
|
||||
|
||||
export class CssAnimationProperty<T extends Style, U> {
|
||||
public readonly name: string;
|
||||
public readonly cssName: string;
|
||||
|
||||
public readonly native: symbol;
|
||||
public readonly register: (cls: { prototype }) => void;
|
||||
|
||||
public readonly keyframe: string;
|
||||
public readonly defaultValueKey: symbol;
|
||||
|
||||
constructor(private options: definitions.CssAnimationPropertyOptions<T, U>) {
|
||||
const { valueConverter, equalityComparer, valueChanged, defaultValue } = options;
|
||||
const propertyName = options.name;
|
||||
this.name = propertyName;
|
||||
this.cssName = (options.cssName || propertyName);
|
||||
|
||||
const cssName = "css:" + (options.cssName || propertyName);
|
||||
const keyframeName = "keyframe:" + propertyName;
|
||||
this.keyframe = keyframeName;
|
||||
const defaultName = "default:" + propertyName;
|
||||
|
||||
const defaultValueKey = Symbol(defaultName);
|
||||
this.defaultValueKey = defaultValueKey;
|
||||
|
||||
const cssValue = Symbol(cssName);
|
||||
const styleValue = Symbol(propertyName);
|
||||
const keyframeValue = Symbol(keyframeName);
|
||||
const computedValue = Symbol("computed-value:" + propertyName);
|
||||
const computedSource = Symbol("computed-source:" + propertyName);
|
||||
|
||||
const native = this.native = Symbol("native:" + propertyName);
|
||||
const eventName = propertyName + "Change";
|
||||
|
||||
function descriptor(symbol: symbol, propertySource: ValueSource, enumerable: boolean, configurable: boolean, getsComputed: boolean): PropertyDescriptor {
|
||||
return { enumerable, configurable,
|
||||
get: getsComputed ? function(this: T) { return this[computedValue]; } : function(this: T) { return this[symbol]; },
|
||||
set(this: T, value: U) {
|
||||
let prev = this[computedValue];
|
||||
if (value === unsetValue) {
|
||||
this[symbol] = unsetValue;
|
||||
if (this[computedSource] == propertySource) {
|
||||
// Fallback to lower value source.
|
||||
if (this[styleValue] !== unsetValue) {
|
||||
this[computedSource] = ValueSource.Local;
|
||||
this[computedValue] = this[styleValue];
|
||||
} else if (this[cssValue] !== unsetValue) {
|
||||
this[computedSource] = ValueSource.Css;
|
||||
this[computedValue] = this[cssValue];
|
||||
} else {
|
||||
this[computedSource] = ValueSource.Default;
|
||||
this[computedValue] = defaultValue;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (valueConverter && typeof value === "string") {
|
||||
value = valueConverter(value);
|
||||
}
|
||||
this[symbol] = value;
|
||||
if (this[computedSource] <= propertySource) {
|
||||
this[computedSource] = propertySource;
|
||||
this[computedValue] = value;
|
||||
}
|
||||
}
|
||||
let next = this[computedValue];
|
||||
if (prev !== next && (!equalityComparer || !equalityComparer(prev, next))) {
|
||||
valueChanged && valueChanged(this, prev, next);
|
||||
this.view.nativeView && (this.view[native] = next);
|
||||
this.hasListeners(eventName) && this.notify({ eventName, object: this, propertyName, value });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const defaultPropertyDescriptor = descriptor(defaultValueKey, ValueSource.Default, false, false, false);
|
||||
const cssPropertyDescriptor = descriptor(cssValue, ValueSource.Css, false, false, false);
|
||||
const stylePropertyDescriptor = descriptor(styleValue, ValueSource.Local, true, true, true);
|
||||
const keyframePropertyDescriptor = descriptor(keyframeValue, ValueSource.Keyframe, false, false, false);
|
||||
|
||||
cssSymbolResetMap[cssValue] = cssName;
|
||||
cssSymbolResetMap[keyframeValue] = keyframeName;
|
||||
|
||||
symbolPropertyMap[computedValue] = this;
|
||||
|
||||
this.register = (cls: { prototype: T }) => {
|
||||
cls.prototype[defaultValueKey] = options.defaultValue;
|
||||
cls.prototype[computedValue] = options.defaultValue;
|
||||
cls.prototype[computedSource] = ValueSource.Default;
|
||||
|
||||
cls.prototype[cssValue] = unsetValue;
|
||||
cls.prototype[styleValue] = unsetValue;
|
||||
cls.prototype[keyframeValue] = unsetValue;
|
||||
|
||||
Object.defineProperty(cls.prototype, defaultName, defaultPropertyDescriptor);
|
||||
Object.defineProperty(cls.prototype, cssName, cssPropertyDescriptor);
|
||||
Object.defineProperty(cls.prototype, propertyName, stylePropertyDescriptor);
|
||||
Object.defineProperty(cls.prototype, keyframeName, keyframePropertyDescriptor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class InheritedCssProperty<T extends Style, U> extends CssProperty<T, U> implements definitions.InheritedCssProperty<T, U> {
|
||||
public setInheritedValue: (value: U) => void;
|
||||
|
||||
@ -690,7 +794,7 @@ export class ShorthandProperty<T extends Style, P> implements definitions.Shorth
|
||||
const key = Symbol(this.name + ":propertyKey");
|
||||
this.key = key;
|
||||
|
||||
this.cssName = `css-${options.cssName}`;
|
||||
this.cssName = `css:${options.cssName}`;
|
||||
this.cssLocalName = `${options.cssName}`;
|
||||
|
||||
const converter = options.converter;
|
||||
@ -872,12 +976,12 @@ export function clearInheritedProperties(view: ViewBase): void {
|
||||
export function resetCSSProperties(style: Style): void {
|
||||
let symbols = (<any>Object).getOwnPropertySymbols(style);
|
||||
for (let symbol of symbols) {
|
||||
const cssProperty = cssSymbolPropertyMap[symbol];
|
||||
if (!cssProperty) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let cssProperty;
|
||||
if (cssProperty = cssSymbolPropertyMap[symbol]) {
|
||||
style[cssProperty.cssName] = unsetValue;
|
||||
} else if (cssProperty = cssSymbolResetMap[symbol]) {
|
||||
style[cssProperty] = unsetValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,7 +4,7 @@ import { Source } from "utils/debug";
|
||||
import { Background } from "ui/styling/background";
|
||||
import {
|
||||
ViewBase, getEventOrGestureName, EventData, Style, unsetValue,
|
||||
Property, CssProperty, ShorthandProperty, InheritedCssProperty,
|
||||
Property, CssProperty, CssAnimationProperty, ShorthandProperty, InheritedCssProperty,
|
||||
gestureFromString, isIOS, traceEnabled, traceWrite, traceCategories, makeParser, makeValidator
|
||||
} from "./view-base";
|
||||
import { observe as gestureObserve, GesturesObserver, GestureTypes, GestureEventData } from "ui/gestures";
|
||||
@ -426,17 +426,17 @@ export abstract class ViewCommon extends ViewBase implements ViewDefinition {
|
||||
this.style.rotate = value;
|
||||
}
|
||||
|
||||
get translateX(): number {
|
||||
get translateX(): Length {
|
||||
return this.style.translateX;
|
||||
}
|
||||
set translateX(value: number) {
|
||||
set translateX(value: Length) {
|
||||
this.style.translateX = value;
|
||||
}
|
||||
|
||||
get translateY(): number {
|
||||
get translateY(): Length {
|
||||
return this.style.translateY;
|
||||
}
|
||||
set translateY(value: number) {
|
||||
set translateY(value: Length) {
|
||||
this.style.translateY = value;
|
||||
}
|
||||
|
||||
@ -1352,19 +1352,19 @@ function convertToPaddings(this: void, value: string | Length): [CssProperty<any
|
||||
}
|
||||
}
|
||||
|
||||
export const rotateProperty = new CssProperty<Style, number>({ name: "rotate", cssName: "rotate", defaultValue: 0, valueConverter: (v) => parseFloat(v) });
|
||||
export const rotateProperty = new CssAnimationProperty<Style, number>({ name: "rotate", cssName: "rotate", defaultValue: 0, valueConverter: parseFloat });
|
||||
rotateProperty.register(Style);
|
||||
|
||||
export const scaleXProperty = new CssProperty<Style, number>({ name: "scaleX", cssName: "scaleX", defaultValue: 1, valueConverter: (v) => parseFloat(v) });
|
||||
export const scaleXProperty = new CssAnimationProperty<Style, number>({ name: "scaleX", cssName: "scaleX", defaultValue: 1, valueConverter: parseFloat });
|
||||
scaleXProperty.register(Style);
|
||||
|
||||
export const scaleYProperty = new CssProperty<Style, number>({ name: "scaleY", cssName: "scaleY", defaultValue: 1, valueConverter: (v) => parseFloat(v) });
|
||||
export const scaleYProperty = new CssAnimationProperty<Style, number>({ name: "scaleY", cssName: "scaleY", defaultValue: 1, valueConverter: parseFloat });
|
||||
scaleYProperty.register(Style);
|
||||
|
||||
export const translateXProperty = new CssProperty<Style, number>({ name: "translateX", cssName: "translateX", defaultValue: 0, valueConverter: (v) => parseFloat(v) });
|
||||
export const translateXProperty = new CssAnimationProperty<Style, Length>({ name: "translateX", cssName: "translateX", defaultValue: 0, valueConverter: Length.parse, equalityComparer: Length.equals });
|
||||
translateXProperty.register(Style);
|
||||
|
||||
export const translateYProperty = new CssProperty<Style, number>({ name: "translateY", cssName: "translateY", defaultValue: 0, valueConverter: (v) => parseFloat(v) });
|
||||
export const translateYProperty = new CssAnimationProperty<Style, Length>({ name: "translateY", cssName: "translateY", defaultValue: 0, valueConverter: Length.parse, equalityComparer: Length.equals });
|
||||
translateYProperty.register(Style);
|
||||
|
||||
const transformProperty = new ShorthandProperty<Style, string>({
|
||||
@ -1545,7 +1545,7 @@ export const backgroundImageProperty = new CssProperty<Style, string>({
|
||||
});
|
||||
backgroundImageProperty.register(Style);
|
||||
|
||||
export const backgroundColorProperty = new CssProperty<Style, Color>({
|
||||
export const backgroundColorProperty = new CssAnimationProperty<Style, Color>({
|
||||
name: "backgroundColor", cssName: "background-color", valueChanged: (target, oldValue, newValue) => {
|
||||
let background = target.backgroundInternal;
|
||||
target.backgroundInternal = background.withColor(newValue);
|
||||
@ -1929,7 +1929,7 @@ function opacityConverter(value: any): number {
|
||||
throw new Error(`Opacity should be between [0, 1]. Value: ${newValue}`);
|
||||
}
|
||||
|
||||
export const opacityProperty = new CssProperty<Style, number>({ name: "opacity", cssName: "opacity", defaultValue: 1, valueConverter: opacityConverter });
|
||||
export const opacityProperty = new CssAnimationProperty<Style, number>({ name: "opacity", cssName: "opacity", defaultValue: 1, valueConverter: opacityConverter });
|
||||
opacityProperty.register(Style);
|
||||
|
||||
export const colorProperty = new InheritedCssProperty<Style, Color>({ name: "color", cssName: "color", equalityComparer: Color.equals, valueConverter: (v) => new Color(v) });
|
||||
|
@ -389,18 +389,18 @@ export class View extends ViewCommon {
|
||||
org.nativescript.widgets.ViewHelper.setScaleY(this.nativeView, float(value));
|
||||
}
|
||||
|
||||
get [translateXProperty.native](): number {
|
||||
get [translateXProperty.native](): Length | number {
|
||||
return org.nativescript.widgets.ViewHelper.getTranslateX(this.nativeView);
|
||||
}
|
||||
set [translateXProperty.native](value: number) {
|
||||
org.nativescript.widgets.ViewHelper.setTranslateX(this.nativeView, float(value));
|
||||
set [translateXProperty.native](value: Length) {
|
||||
org.nativescript.widgets.ViewHelper.setTranslateX(this.nativeView, Length.toDevicePixels(value, 0));
|
||||
}
|
||||
|
||||
get [translateYProperty.native](): number {
|
||||
get [translateYProperty.native](): Length | number {
|
||||
return org.nativescript.widgets.ViewHelper.getTranslateY(this.nativeView);
|
||||
}
|
||||
set [translateYProperty.native](value: number) {
|
||||
org.nativescript.widgets.ViewHelper.setTranslateY(this.nativeView, float(value));
|
||||
set [translateYProperty.native](value: Length) {
|
||||
org.nativescript.widgets.ViewHelper.setTranslateY(this.nativeView, Length.toDevicePixels(value, 0));
|
||||
}
|
||||
|
||||
get [zIndexProperty.native](): number {
|
||||
|
20
tns-core-modules/ui/core/view.d.ts
vendored
20
tns-core-modules/ui/core/view.d.ts
vendored
@ -1,7 +1,7 @@
|
||||
declare module "ui/core/view" {
|
||||
import { GestureTypes, GesturesObserver, GestureEventData, TouchGestureEventData, TouchAction } from "ui/gestures";
|
||||
import {
|
||||
ViewBase, Property, CssProperty, InheritedCssProperty, Style, EventData, ShorthandProperty
|
||||
ViewBase, Property, CssProperty, CssAnimationProperty, InheritedCssProperty, Style, EventData, ShorthandProperty
|
||||
} from "ui/core/view-base";
|
||||
import { Background } from "ui/styling/background";
|
||||
import { Font, FontWeight, FontStyle } from "ui/styling/font";
|
||||
@ -293,12 +293,12 @@ declare module "ui/core/view" {
|
||||
/**
|
||||
* Gets or sets the translateX affine transform of the view.
|
||||
*/
|
||||
translateX: number;
|
||||
translateX: Length;
|
||||
|
||||
/**
|
||||
* Gets or sets the translateY affine transform of the view.
|
||||
*/
|
||||
translateY: number;
|
||||
translateY: Length;
|
||||
|
||||
/**
|
||||
* Gets or sets the scaleX affine transform of the view.
|
||||
@ -702,16 +702,16 @@ declare module "ui/core/view" {
|
||||
export const isEnabledProperty: Property<View, boolean>;
|
||||
export const isUserInteractionEnabledProperty: Property<View, boolean>;
|
||||
|
||||
export const rotateProperty: CssProperty<Style, number>;
|
||||
export const scaleXProperty: CssProperty<Style, number>;
|
||||
export const scaleYProperty: CssProperty<Style, number>;
|
||||
export const translateXProperty: CssProperty<Style, number>;
|
||||
export const translateYProperty: CssProperty<Style, number>;
|
||||
export const rotateProperty: CssAnimationProperty<Style, number>;
|
||||
export const scaleXProperty: CssAnimationProperty<Style, number>;
|
||||
export const scaleYProperty: CssAnimationProperty<Style, number>;
|
||||
export const translateXProperty: CssAnimationProperty<Style, Length>;
|
||||
export const translateYProperty: CssAnimationProperty<Style, Length>;
|
||||
|
||||
export const clipPathProperty: CssProperty<Style, string>;
|
||||
export const colorProperty: InheritedCssProperty<Style, Color>;
|
||||
|
||||
export const backgroundColorProperty: CssProperty<Style, Color>;
|
||||
export const backgroundColorProperty: CssAnimationProperty<Style, Color>;
|
||||
export const backgroundImageProperty: CssProperty<Style, string>;
|
||||
export const backgroundRepeatProperty: CssProperty<Style, BackgroundRepeat>;
|
||||
export const backgroundSizeProperty: CssProperty<Style, string>;
|
||||
@ -737,7 +737,7 @@ declare module "ui/core/view" {
|
||||
|
||||
export const zIndexProperty: CssProperty<Style, number>;
|
||||
export const visibilityProperty: CssProperty<Style, Visibility>;
|
||||
export const opacityProperty: CssProperty<Style, number>;
|
||||
export const opacityProperty: CssAnimationProperty<Style, number>;
|
||||
|
||||
export const minWidthProperty: CssProperty<Style, Length>;
|
||||
export const minHeightProperty: CssProperty<Style, Length>;
|
||||
|
@ -4,7 +4,7 @@ import {
|
||||
ViewCommon, isEnabledProperty, originXProperty, originYProperty, automationTextProperty, isUserInteractionEnabledProperty, visibilityProperty, opacityProperty,
|
||||
rotateProperty, scaleXProperty, scaleYProperty,
|
||||
translateXProperty, translateYProperty, zIndexProperty, backgroundInternalProperty,
|
||||
clipPathProperty, layout, traceEnabled, traceWrite, traceCategories, Background, Visibility
|
||||
clipPathProperty, layout, traceEnabled, traceWrite, traceCategories, Background, Visibility, Length
|
||||
} from "./view-common";
|
||||
|
||||
export * from "./view-common";
|
||||
@ -232,8 +232,8 @@ export class View extends ViewCommon {
|
||||
}
|
||||
|
||||
public updateNativeTransform() {
|
||||
let translateX = this.translateX || 0;
|
||||
let translateY = this.translateY || 0;
|
||||
let translateX = Length.toDevicePixels(this.translateX || 0, 0);
|
||||
let translateY = Length.toDevicePixels(this.translateY || 0, 0);
|
||||
let scaleX = this.scaleX || 1;
|
||||
let scaleY = this.scaleY || 1;
|
||||
let rotate = this.rotate || 0;
|
||||
@ -363,17 +363,17 @@ export class View extends ViewCommon {
|
||||
this.updateNativeTransform();
|
||||
}
|
||||
|
||||
get [translateXProperty.native](): number {
|
||||
get [translateXProperty.native](): Length | number {
|
||||
return 0;
|
||||
}
|
||||
set [translateXProperty.native](value: number) {
|
||||
set [translateXProperty.native](value: Length) {
|
||||
this.updateNativeTransform();
|
||||
}
|
||||
|
||||
get [translateYProperty.native](): number {
|
||||
get [translateYProperty.native](): Length | number {
|
||||
return 0;
|
||||
}
|
||||
set [translateYProperty.native](value: number) {
|
||||
set [translateYProperty.native](value: Length) {
|
||||
this.updateNativeTransform();
|
||||
}
|
||||
|
||||
|
21
tns-core-modules/ui/definitions.d.ts
vendored
21
tns-core-modules/ui/definitions.d.ts
vendored
@ -217,6 +217,27 @@ declare module "ui/core/properties" {
|
||||
readonly cssName: string;
|
||||
}
|
||||
|
||||
export interface CssAnimationPropertyOptions<T, U> {
|
||||
readonly name: string;
|
||||
readonly cssName?: string;
|
||||
readonly defaultValue?: U;
|
||||
readonly equalityComparer?: (x: U, y: U) => boolean;
|
||||
readonly valueChanged?: (target: T, oldValue: U, newValue: U) => void;
|
||||
readonly valueConverter?: (value: string) => U;
|
||||
}
|
||||
|
||||
export class CssAnimationProperty<T extends Style, U> {
|
||||
constructor(options: CssAnimationPropertyOptions<T, U>);
|
||||
|
||||
public readonly name: string;
|
||||
public readonly cssName: string;
|
||||
public readonly native: symbol;
|
||||
|
||||
readonly keyframe: string;
|
||||
|
||||
public register(cls: { prototype: T }): void;
|
||||
}
|
||||
|
||||
export class Property<T extends ViewBase, U> implements TypedPropertyDescriptor<U> {
|
||||
constructor(options: PropertyOptions<T, U>);
|
||||
|
||||
|
@ -113,7 +113,7 @@ imageSourceProperty.register(ImageBase);
|
||||
export const srcProperty = new Property<ImageBase, any>({ name: "src"});
|
||||
srcProperty.register(ImageBase);
|
||||
|
||||
export const loadModeProperty = new Property<ImageBase, "sync" | "async">({ name: "loadMode", defaultValue: "async" });
|
||||
export const loadModeProperty = new Property<ImageBase, "sync" | "async">({ name: "loadMode", defaultValue: "sync" });
|
||||
loadModeProperty.register(ImageBase);
|
||||
|
||||
export const isLoadingProperty = new Property<ImageBase, boolean>({ name: "isLoading", defaultValue: false, valueConverter: booleanConverter });
|
||||
|
@ -25,9 +25,12 @@ export class Image extends ImageBase {
|
||||
}
|
||||
|
||||
private setTintColor(value: Color) {
|
||||
if (value !== null && this._ios.image && !this._templateImageWasCreated) {
|
||||
if (value && this._ios.image && !this._templateImageWasCreated) {
|
||||
this._ios.image = this._ios.image.imageWithRenderingMode(UIImageRenderingMode.AlwaysTemplate);
|
||||
this._templateImageWasCreated = true;
|
||||
} else if (this._ios.image && this._templateImageWasCreated) {
|
||||
this._templateImageWasCreated = false;
|
||||
this._ios.image = this._ios.image.imageWithRenderingMode(UIImageRenderingMode.Automatic);
|
||||
}
|
||||
this._ios.tintColor = value ? value.ios : null;
|
||||
}
|
||||
|
@ -49,8 +49,8 @@ export class CssState {
|
||||
let style = view.style;
|
||||
ruleset.declarations.forEach(d => {
|
||||
try {
|
||||
// Use the "css-" prefixed name, so that CSS value source is set.
|
||||
let cssPropName = `css-${d.property}`;
|
||||
// Use the "css:" prefixed name, so that CSS value source is set.
|
||||
let cssPropName = `css:${d.property}`;
|
||||
if (cssPropName in style) {
|
||||
style[cssPropName] = d.value;
|
||||
} else {
|
||||
|
4
tns-core-modules/ui/styling/style.d.ts
vendored
4
tns-core-modules/ui/styling/style.d.ts
vendored
@ -46,8 +46,8 @@ declare module "ui/styling/style" {
|
||||
public rotate: number;
|
||||
public scaleX: number;
|
||||
public scaleY: number;
|
||||
public translateX: number;
|
||||
public translateY: number;
|
||||
public translateX: Length;
|
||||
public translateY: Length;
|
||||
|
||||
public clipPath: string;
|
||||
public color: Color;
|
||||
|
Reference in New Issue
Block a user