From cc92fc329f69beef97c22ac3ab24c94e9736e566 Mon Sep 17 00:00:00 2001 From: Tsvetan Raikov Date: Tue, 9 Feb 2016 14:50:32 +0200 Subject: [PATCH 1/5] Added custom animation curve support and spring animations --- tsconfig.json | 1 - ui/animation/animation-common.ts | 17 +++- ui/animation/animation.android.ts | 21 +++-- ui/animation/animation.d.ts | 28 ++++-- ui/animation/animation.ios.ts | 137 ++++++++++++++++++++++++++++-- ui/enums/enums.d.ts | 47 +++++----- ui/enums/enums.ts | 3 +- 7 files changed, 212 insertions(+), 42 deletions(-) diff --git a/tsconfig.json b/tsconfig.json index 482b8cbb0..cc5fd65f9 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -53,7 +53,6 @@ "apps/connectivity-demo/app.ts", "apps/connectivity-demo/main-page.ts", "apps/custom-root-view/app.ts", - "apps/custom-root-view/list-view.ts", "apps/cuteness.io/app.ts", "apps/cuteness.io/details-page.ts", "apps/cuteness.io/main-page.ts", diff --git a/ui/animation/animation-common.ts b/ui/animation/animation-common.ts index dd58ce806..18d68880c 100644 --- a/ui/animation/animation-common.ts +++ b/ui/animation/animation-common.ts @@ -27,6 +27,21 @@ export interface PropertyAnimation { curve?: any; } +export class CustomAnimationCurve implements definition.CustomAnimationCurve { + + public x1: number; + public y1: number; + public x2: number; + public y2: number; + + constructor(x1: number, y1: number, x2: number, y2: number) { + this.x1 = x1; + this.y1 = y1; + this.x2 = x2; + this.y2 = y2; + } +} + export class Animation implements definition.Animation { public _propertyAnimations: Array; public _playSequentially: boolean; @@ -98,7 +113,7 @@ export class Animation implements definition.Animation { } var propertyAnimations = new Array(); - + // opacity if (animationDefinition.opacity !== undefined) { propertyAnimations.push({ diff --git a/ui/animation/animation.android.ts b/ui/animation/animation.android.ts index cf5c4648a..1ef913d9b 100644 --- a/ui/animation/animation.android.ts +++ b/ui/animation/animation.android.ts @@ -26,7 +26,7 @@ propertyKeys[common.Properties.translate] = Symbol(keyPrefix + common.Properties export class Animation extends common.Animation implements definition.Animation { private _animatorListener: android.animation.Animator.AnimatorListener; private _nativeAnimatorsArray: any; - private _animatorSet: android.animation.AnimatorSet; + private _animatorSet: android.animation.AnimatorSet; private _animators: Array; private _propertyUpdateCallbacks: Array; private _propertyResetCallbacks: Array; @@ -102,7 +102,7 @@ export class Animation extends common.Animation implements definition.Animation // It has been cancelled return; } - + var i = 0; var length = this._propertyUpdateCallbacks.length; for (; i < length; i++) { @@ -145,7 +145,7 @@ export class Animation extends common.Animation implements definition.Animation var density = utils.layout.getDisplayDensity(); var xyObjectAnimators: any; var animatorSet: android.animation.AnimatorSet; - + var key = propertyKeys[propertyAnimation.property]; if (key) { propertyAnimation.target[key] = propertyAnimation; @@ -158,7 +158,7 @@ export class Animation extends common.Animation implements definition.Animation } } } - + switch (propertyAnimation.property) { case common.Properties.opacity: @@ -270,7 +270,7 @@ export class Animation extends common.Animation implements definition.Animation var i = 0; var length = animators.length; for (; i < length; i++) { - + // Duration if (propertyAnimation.duration !== undefined) { animators[i].setDuration(propertyAnimation.duration); @@ -281,7 +281,7 @@ export class Animation extends common.Animation implements definition.Animation animators[i].setStartDelay(propertyAnimation.delay); } - // Repeat Count + // Repeat Count if (propertyAnimation.iterations !== undefined && animators[i] instanceof android.animation.ValueAnimator) { (animators[i]).setRepeatCount(Animation._getAndroidRepeatCount(propertyAnimation.iterations)); } @@ -307,6 +307,7 @@ var easeIn = new android.view.animation.AccelerateInterpolator(1); var easeOut = new android.view.animation.DecelerateInterpolator(1); var easeInOut = new android.view.animation.AccelerateDecelerateInterpolator(); var linear = new android.view.animation.LinearInterpolator(); +var bounce = new android.view.animation.BounceInterpolator(); export function _resolveAnimationCurve(curve: any): any { switch (curve) { case enums.AnimationCurve.easeIn: @@ -321,8 +322,16 @@ export function _resolveAnimationCurve(curve: any): any { case enums.AnimationCurve.linear: trace.write("Animation curve resolved to android.view.animation.LinearInterpolator().", trace.categories.Animation); return linear; + case enums.AnimationCurve.spring: + trace.write("Animation curve resolved to android.view.animation.BounceInterpolator().", trace.categories.Animation); + return bounce; default: trace.write("Animation curve resolved to original: " + curve, trace.categories.Animation); + if (curve instanceof common.CustomAnimationCurve) { + var animationCurve = curve; + var interpolator = (((android.support.v4.view).animation).PathInterpolatorCompat).create(animationCurve.x1, animationCurve.y1, animationCurve.x2, animationCurve.y2); + return interpolator; + } return curve; } } diff --git a/ui/animation/animation.d.ts b/ui/animation/animation.d.ts index 028ece8b8..7349ca98d 100644 --- a/ui/animation/animation.d.ts +++ b/ui/animation/animation.d.ts @@ -7,10 +7,10 @@ */ export interface AnimationDefinition { /** - * The view whose property is to be animated. + * The view whose property is to be animated. */ target?: viewModule.View; - + /** * Animates the opacity of the view. Value should be a number between 0.0 and 1.0 */ @@ -35,24 +35,24 @@ * Animates the rotate affine transform of the view. Value should be a number specifying the rotation amount in degrees. */ rotate?: number; - + /** * The length of the animation in milliseconds. The default duration is 300 milliseconds. */ duration?: number; /** - * The amount of time, in milliseconds, to delay starting the animation. + * The amount of time, in milliseconds, to delay starting the animation. */ delay?: number; - + /** * Specifies how many times the animation should be played. Default is 1. * iOS animations support fractional iterations, i.e. 1.5. * To repeat an animation infinitely, use Number.POSITIVE_INFINITY */ iterations?: number; - + /** * An optional animation curve. Possible values are contained in the [AnimationCurve enumeration](../enums/AnimationCurve/README.md). * Alternatively, you can pass an instance of type UIViewAnimationCurve for iOS or android.animation.TimeInterpolator for Android. @@ -60,6 +60,20 @@ curve?: any; } + /** + * Defines a custom animation timing curve by using the cubic-bezier function. + * Possible values are numeric values from 0 to 1 + */ + export class CustomAnimationCurve { + + public x1: number; + public y1: number; + public x2: number; + public y2: number; + + constructor(x1: number, y1: number, x2: number, y2: number); + } + /** * Defines a pair of values (horizontal and vertical) for translate and scale animations. */ @@ -81,4 +95,4 @@ //@private export function _resolveAnimationCurve(curve: any): any; //@endprivate -} \ No newline at end of file +} diff --git a/ui/animation/animation.ios.ts b/ui/animation/animation.ios.ts index c6d4295c2..542710fec 100644 --- a/ui/animation/animation.ios.ts +++ b/ui/animation/animation.ios.ts @@ -11,6 +11,8 @@ var _skip = "_skip"; var FLT_MAX = 340282346638528859811704183484516925440.000000; +declare var CASpringAnimation:any; + class AnimationDelegateImpl extends NSObject { public nextAnimation: Function; @@ -73,6 +75,27 @@ class AnimationDelegateImpl extends NSObject { this.nextAnimation(); } } + + public uiview_animationWillStart(animationID: string, context: any): void { + trace.write("AnimationDelegateImpl.animationWillStart, animationID: " + animationID, trace.categories.Animation); + } + + public uiview_animationDidStop(animationID: string, finished: boolean, context: any): void { + trace.write("AnimationDelegateImpl.animationDidStop, animationID: " + animationID + ", finished: " + finished, trace.categories.Animation); + if (this._finishedCallback) { + var cancelled = !finished; + // This could either be the master finishedCallback or an nextAnimationCallback depending on the playSequentially argument values. + this._finishedCallback(cancelled); + } + if (!finished) { + if ((this._propertyAnimation)._propertyResetCallback) { + (this._propertyAnimation)._propertyResetCallback((this._propertyAnimation)._originalValue); + } + } + if (finished && this.nextAnimation) { + this.nextAnimation(); + } + } } export class Animation extends common.Animation implements definition.Animation { @@ -149,6 +172,7 @@ export class Animation extends common.Animation implements definition.Animation finishedCallback(cancelled); return; } + var animation = propertyAnimations[index]; var nativeView = animation.target._nativeView; var propertyNameToAnimate = animation.property; @@ -163,11 +187,18 @@ export class Animation extends common.Animation implements definition.Animation (animation)._originalValue = animation.target.backgroundColor; (animation)._propertyResetCallback = (value) => { animation.target.backgroundColor = value }; if (presentationLayer != null) { + if (nativeView instanceof UILabel) { + nativeView.backgroundColor = UIColor.clearColor(); + } originalValue = presentationLayer.backgroundColor; } else { originalValue = nativeView.layer.backgroundColor; } + if (nativeView instanceof UILabel) { + originalValue = nativeView.layer.backgroundColor; + nativeView.setValueForKey(UIColor.clearColor(), "backgroundColor"); + } value = value.CGColor; break; case common.Properties.opacity: @@ -242,15 +273,100 @@ export class Animation extends common.Animation implements definition.Animation throw new Error("Cannot animate " + animation.property); } - var nativeAnimation = CABasicAnimation.animationWithKeyPath(propertyNameToAnimate); + var nativeAnimation; + var isSpring = false; + + if (animation.curve === enums.AnimationCurve.spring) { + + // nativeAnimation = CASpringAnimation.animationWithKeyPath(propertyNameToAnimate); + // nativeAnimation.duration = nativeAnimation.settlingDuration; + // nativeAnimation.damping = 3; + + var duration = 0.3; + if (animation.duration !== undefined) { + duration = animation.duration / 1000.0; + } + var delay = 0; + if (animation.delay !== undefined) { + delay = CACurrentMediaTime() + (animation.delay / 1000.0); + } + + var animationDelegate: AnimationDelegateImpl; + animationDelegate = AnimationDelegateImpl.initWithFinishedCallback(finishedCallback, animation); + + var callback = undefined; + if (index+1 < propertyAnimations.length) { + callback = Animation._createiOSAnimationFunction(propertyAnimations, index+1, playSequentially, finishedCallback, that); + if (!playSequentially) { + callback(); + } + else { + animationDelegate.nextAnimation = callback; + } + } + + UIView.animateWithDurationDelayUsingSpringWithDampingInitialSpringVelocityOptionsAnimationsCompletion(duration, delay, 0.2, 0, + UIViewKeyframeAnimationOptions.UIViewKeyframeAnimationOptionCalculationModeLinear, + () => { + + if (animationDelegate) { + UIView.setAnimationDelegate(animationDelegate); + UIView.setAnimationWillStartSelector("uiview_animationWillStart"); + UIView.setAnimationDidStopSelector("uiview_animationDidStop"); + } + + if (animation.iterations !== undefined) { + if (animation.iterations === Number.POSITIVE_INFINITY) { + UIView.setAnimationRepeatCount(FLT_MAX); + } + else { + UIView.setAnimationRepeatCount(animation.iterations - 1); + } + } + + switch (animation.property) { + case common.Properties.backgroundColor: + animation.target.backgroundColor = value; + break; + case common.Properties.opacity: + animation.target.opacity = value; + break; + case common.Properties.rotate: + nativeView.layer.setValueForKey(value, propertyNameToAnimate); + break; + case _transform: + nativeView.layer.setValueForKey(value, propertyNameToAnimate); + break; + } + + }, function (finished:boolean) { + if (finished) { + if (animation.property === _transform) { + if (animation.value[common.Properties.translate] !== undefined) { + animation.target.translateX = animation.value[common.Properties.translate].x; + animation.target.translateY = animation.value[common.Properties.translate].y; + } + if (animation.value[common.Properties.scale] !== undefined) { + animation.target.scaleX = animation.value[common.Properties.scale].x; + animation.target.scaleY = animation.value[common.Properties.scale].y; + } + } + } + }); + + return; + } + else { + nativeAnimation = CABasicAnimation.animationWithKeyPath(propertyNameToAnimate); + } nativeAnimation.fromValue = originalValue; - nativeAnimation.toValue = value; + nativeAnimation.toValue = value; if (animation.duration !== undefined) { nativeAnimation.duration = animation.duration / 1000.0; } else { nativeAnimation.duration = 0.3; - }; + } if (animation.delay !== undefined) { nativeAnimation.beginTime = CACurrentMediaTime() + (animation.delay / 1000.0); } @@ -263,7 +379,7 @@ export class Animation extends common.Animation implements definition.Animation nativeAnimation.repeatCount = animation.iterations - 1; } } - if (animation.curve !== undefined) { + if (!isSpring && animation.curve !== undefined) { trace.write("The animation curve is " + animation.curve, trace.categories.Animation); nativeAnimation.timingFunction = animation.curve; } @@ -353,8 +469,10 @@ export class Animation extends common.Animation implements definition.Animation value: {}, duration: propertyAnimations[i].duration, delay: propertyAnimations[i].delay, - iterations: propertyAnimations[i].iterations + iterations: propertyAnimations[i].iterations, + curve: propertyAnimations[i].curve }; + trace.write("Curve: " + propertyAnimations[i].curve, trace.categories.Animation); newTransformAnimation.value[propertyAnimations[i].property] = propertyAnimations[i].value; trace.write("Created new transform animation: " + common.Animation._getAnimationInfo(newTransformAnimation), trace.categories.Animation); @@ -388,7 +506,16 @@ export function _resolveAnimationCurve(curve: any): any { return CAMediaTimingFunction.functionWithName(kCAMediaTimingFunctionEaseInEaseOut); case enums.AnimationCurve.linear: return CAMediaTimingFunction.functionWithName(kCAMediaTimingFunctionLinear); + case enums.AnimationCurve.spring: + return curve; default: + if (curve instanceof CAMediaTimingFunction) { + return curve; + } + else if (curve instanceof common.CustomAnimationCurve) { + var animationCurve = curve; + return CAMediaTimingFunction.functionWithControlPoints(animationCurve.x1, animationCurve.y1, animationCurve.x2, animationCurve.y2); + } return undefined; } } diff --git a/ui/enums/enums.d.ts b/ui/enums/enums.d.ts index 36a370753..bbaa19bcd 100644 --- a/ui/enums/enums.d.ts +++ b/ui/enums/enums.d.ts @@ -9,25 +9,25 @@ * iOS: [UIKeyboardTypeNumbersAndPunctuation](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UITextInputTraits_Protocol/index.html#//apple_ref/c/tdef/UIKeyboardType) */ export var datetime: string; - + /** * Android: [TYPE_CLASS_PHONE](http://developer.android.com/reference/android/text/InputType.html#TYPE_CLASS_PHONE) * iOS: [UIKeyboardTypePhonePad](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UITextInputTraits_Protocol/index.html#//apple_ref/c/tdef/UIKeyboardType) */ export var phone: string; - + /** * Android: [TYPE_CLASS_NUMBER](http://developer.android.com/reference/android/text/InputType.html#TYPE_CLASS_NUMBER) | android.text.InputType.TYPE_NUMBER_VARIATION_NORMAL | [TYPE_NUMBER_FLAG_SIGNED](http://developer.android.com/reference/android/text/InputType.html#TYPE_NUMBER_FLAG_SIGNED) | [TYPE_NUMBER_FLAG_DECIMAL](http://developer.android.com/reference/android/text/InputType.html#TYPE_NUMBER_FLAG_DECIMAL) * iOS: [UIKeyboardTypeNumbersAndPunctuation](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UITextInputTraits_Protocol/index.html#//apple_ref/c/tdef/UIKeyboardType) */ export var number: string; - + /** * Android: [TYPE_CLASS_TEXT](http://developer.android.com/reference/android/text/InputType.html#TYPE_CLASS_TEXT) | [TYPE_TEXT_VARIATION_URI](http://developer.android.com/reference/android/text/InputType.html#TYPE_TEXT_VARIATION_URI) * iOS: [UIKeyboardTypeURL](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UITextInputTraits_Protocol/index.html#//apple_ref/c/tdef/UIKeyboardType) */ export var url: string; - + /** * Android: [TYPE_CLASS_TEXT](http://developer.android.com/reference/android/text/InputType.html#TYPE_CLASS_TEXT) | [TYPE_TEXT_VARIATION_EMAIL_ADDRESS](http://developer.android.com/reference/android/text/InputType.html#TYPE_TEXT_VARIATION_EMAIL_ADDRESS) * iOS: [UIKeyboardTypeEmailAddress](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UITextInputTraits_Protocol/index.html#//apple_ref/c/tdef/UIKeyboardType) @@ -56,13 +56,13 @@ * iOS: [UIReturnKeyGo](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UITextInputTraits_Protocol/index.html#//apple_ref/c/tdef/UIReturnKeyType) */ export var go: string; - + /** * Android: [IME_ACTION_SEARCH](http://developer.android.com/reference/android/view/inputmethod/EditorInfo.html#IME_ACTION_SEARCH) * iOS: [UIReturnKeySearch](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UITextInputTraits_Protocol/index.html#//apple_ref/c/tdef/UIReturnKeyType) */ export var search: string; - + /** * Android: [IME_ACTION_SEND](http://developer.android.com/reference/android/view/inputmethod/EditorInfo.html#IME_ACTION_SEND) * iOS: [UIReturnKeySend](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UITextInputTraits_Protocol/index.html#//apple_ref/c/tdef/UIReturnKeyType) @@ -324,17 +324,17 @@ export var none: string; /** - * Capitalize the first letter of each word automatically. + * Capitalize the first letter of each word automatically. */ export var words: string; /** - * Capitalize the first letter of each sentence automatically. + * Capitalize the first letter of each sentence automatically. */ export var sentences: string; - + /** - * Capitalize all characters automatically. + * Capitalize all characters automatically. */ export var allCharacters: string; } @@ -402,7 +402,7 @@ */ export var popup: string; } - + /** * Specifies different font styles. */ @@ -411,7 +411,7 @@ * Normal font style. */ export var normal: string; - + /** * Italic font style. */ @@ -426,7 +426,7 @@ * No decoration. */ export var none: string; - + /** * Text decoration underline. */ @@ -446,7 +446,7 @@ * No transform. */ export var none: string; - + /** * Text transform capitalize. */ @@ -456,7 +456,7 @@ * Text transform uppercase. */ export var uppercase: string; - + /** * Text transform lowercase. */ @@ -471,13 +471,13 @@ * Normal wrap. */ export var normal: string; - + /** * No wrap. */ export var nowrap: string; } - + /** * Specifies different font weights. */ @@ -486,13 +486,13 @@ * Normal font weight. */ export var normal: string; - + /** * Bold font weight. */ export var bold: string; } - + /** * Specifies background repeat. */ @@ -536,10 +536,15 @@ * An ease-in ease-out curve causes the animation to begin slowly, accelerate through the middle of its duration, and then slow again before completing. */ export var easeInOut: string; - + /** * A linear animation curve causes an animation to occur evenly over its duration. */ export var linear: string; + + /** + * A spring animation curve causes an animation to produce a spring (bounce) effect. + */ + export var spring: string; } -} \ No newline at end of file +} diff --git a/ui/enums/enums.ts b/ui/enums/enums.ts index 5fe522f3d..52cd0e4b5 100644 --- a/ui/enums/enums.ts +++ b/ui/enums/enums.ts @@ -162,4 +162,5 @@ export module AnimationCurve { export var easeOut = "easeOut"; export var easeInOut = "easeInOut"; export var linear = "linear"; -} \ No newline at end of file + export var spring = "spring"; +} From 4042fecf1e225c086f23717eda4a8ab3f570a808 Mon Sep 17 00:00:00 2001 From: Tsvetan Raikov Date: Tue, 9 Feb 2016 15:38:55 +0200 Subject: [PATCH 2/5] Fixed: animation chaining is not working when using spring animation --- ui/animation/animation.ios.ts | 84 +++++++++++++++++++---------------- 1 file changed, 45 insertions(+), 39 deletions(-) diff --git a/ui/animation/animation.ios.ts b/ui/animation/animation.ios.ts index 542710fec..aa8ec1756 100644 --- a/ui/animation/animation.ios.ts +++ b/ui/animation/animation.ios.ts @@ -57,7 +57,6 @@ class AnimationDelegateImpl extends NSObject { } (this._propertyAnimation.target)._resumePresentationLayerUpdates(); - } public animationDidStopFinished(anim: CAAnimation, flag: boolean): void { @@ -76,26 +75,26 @@ class AnimationDelegateImpl extends NSObject { } } - public uiview_animationWillStart(animationID: string, context: any): void { - trace.write("AnimationDelegateImpl.animationWillStart, animationID: " + animationID, trace.categories.Animation); - } - - public uiview_animationDidStop(animationID: string, finished: boolean, context: any): void { - trace.write("AnimationDelegateImpl.animationDidStop, animationID: " + animationID + ", finished: " + finished, trace.categories.Animation); - if (this._finishedCallback) { - var cancelled = !finished; - // This could either be the master finishedCallback or an nextAnimationCallback depending on the playSequentially argument values. - this._finishedCallback(cancelled); - } - if (!finished) { - if ((this._propertyAnimation)._propertyResetCallback) { - (this._propertyAnimation)._propertyResetCallback((this._propertyAnimation)._originalValue); - } - } - if (finished && this.nextAnimation) { - this.nextAnimation(); - } - } + // public uiview_animationWillStart(animationID: string, context: any): void { + // trace.write("AnimationDelegateImpl.animationWillStart, animationID: " + animationID, trace.categories.Animation); + // } + // + // public uiview_animationDidStop(animationID: string, finished: boolean, context: any): void { + // trace.write("AnimationDelegateImpl.animationDidStop, animationID: " + animationID + ", finished: " + finished, trace.categories.Animation); + // if (this._finishedCallback) { + // var cancelled = !finished; + // // This could either be the master finishedCallback or an nextAnimationCallback depending on the playSequentially argument values. + // this._finishedCallback(cancelled); + // } + // if (!finished) { + // if ((this._propertyAnimation)._propertyResetCallback) { + // (this._propertyAnimation)._propertyResetCallback((this._propertyAnimation)._originalValue); + // } + // } + // if (finished && this.nextAnimation) { + // this.nextAnimation(); + // } + // } } export class Animation extends common.Animation implements definition.Animation { @@ -291,30 +290,21 @@ export class Animation extends common.Animation implements definition.Animation delay = CACurrentMediaTime() + (animation.delay / 1000.0); } - var animationDelegate: AnimationDelegateImpl; - animationDelegate = AnimationDelegateImpl.initWithFinishedCallback(finishedCallback, animation); - var callback = undefined; - if (index+1 < propertyAnimations.length) { - callback = Animation._createiOSAnimationFunction(propertyAnimations, index+1, playSequentially, finishedCallback, that); - if (!playSequentially) { + var nextAnimation; + if (index + 1 < propertyAnimations.length) { + callback = Animation._createiOSAnimationFunction(propertyAnimations, index + 1, playSequentially, finishedCallback, that); + if (!playSequentially) { callback(); - } - else { - animationDelegate.nextAnimation = callback; - } - } + } + else { + nextAnimation = callback; + } + } UIView.animateWithDurationDelayUsingSpringWithDampingInitialSpringVelocityOptionsAnimationsCompletion(duration, delay, 0.2, 0, UIViewKeyframeAnimationOptions.UIViewKeyframeAnimationOptionCalculationModeLinear, () => { - - if (animationDelegate) { - UIView.setAnimationDelegate(animationDelegate); - UIView.setAnimationWillStartSelector("uiview_animationWillStart"); - UIView.setAnimationDidStopSelector("uiview_animationDidStop"); - } - if (animation.iterations !== undefined) { if (animation.iterations === Number.POSITIVE_INFINITY) { UIView.setAnimationRepeatCount(FLT_MAX); @@ -335,7 +325,11 @@ export class Animation extends common.Animation implements definition.Animation nativeView.layer.setValueForKey(value, propertyNameToAnimate); break; case _transform: + (animation)._originalValue = nativeView.layer.transform; nativeView.layer.setValueForKey(value, propertyNameToAnimate); + (animation)._propertyResetCallback = function (value) { + nativeView.layer.transform = value; + } break; } @@ -352,6 +346,18 @@ export class Animation extends common.Animation implements definition.Animation } } } + else { + if ((animation)._propertyResetCallback) { + (animation)._propertyResetCallback((animation)._originalValue); + } + } + if (finishedCallback) { + var cancelled = !finished; + finishedCallback(cancelled); + } + if (finished && nextAnimation) { + nextAnimation(); + } }); return; From 57af0bbfe30b3e8d407a38b81005edbb186b7713 Mon Sep 17 00:00:00 2001 From: Tsvetan Raikov Date: Tue, 9 Feb 2016 18:18:37 +0200 Subject: [PATCH 3/5] Code refactoring --- ui/animation/animation.ios.ts | 505 +++++++++++++++++----------------- 1 file changed, 252 insertions(+), 253 deletions(-) diff --git a/ui/animation/animation.ios.ts b/ui/animation/animation.ios.ts index aa8ec1756..c565740f6 100644 --- a/ui/animation/animation.ios.ts +++ b/ui/animation/animation.ios.ts @@ -13,6 +13,16 @@ var FLT_MAX = 340282346638528859811704183484516925440.000000; declare var CASpringAnimation:any; +class AnimationInfo +{ + public propertyNameToAnimate: string; + public fromValue: any; + public toValue: any; + public duration: number; + public repeatCount: number; + public delay: number; +} + class AnimationDelegateImpl extends NSObject { public nextAnimation: Function; @@ -59,42 +69,19 @@ class AnimationDelegateImpl extends NSObject { (this._propertyAnimation.target)._resumePresentationLayerUpdates(); } - public animationDidStopFinished(anim: CAAnimation, flag: boolean): void { + public animationDidStopFinished(anim: CAAnimation, finished: boolean): void { if (this._finishedCallback) { - var cancelled = !flag; - // This could either be the master finishedCallback or an nextAnimationCallback depending on the playSequentially argument values. - this._finishedCallback(cancelled); + this._finishedCallback(!finished); } - if (!flag) { + if (!finished) { if ((this._propertyAnimation)._propertyResetCallback) { (this._propertyAnimation)._propertyResetCallback((this._propertyAnimation)._originalValue); } } - if (flag && this.nextAnimation) { + if (finished && this.nextAnimation) { this.nextAnimation(); } } - - // public uiview_animationWillStart(animationID: string, context: any): void { - // trace.write("AnimationDelegateImpl.animationWillStart, animationID: " + animationID, trace.categories.Animation); - // } - // - // public uiview_animationDidStop(animationID: string, finished: boolean, context: any): void { - // trace.write("AnimationDelegateImpl.animationDidStop, animationID: " + animationID + ", finished: " + finished, trace.categories.Animation); - // if (this._finishedCallback) { - // var cancelled = !finished; - // // This could either be the master finishedCallback or an nextAnimationCallback depending on the playSequentially argument values. - // this._finishedCallback(cancelled); - // } - // if (!finished) { - // if ((this._propertyAnimation)._propertyResetCallback) { - // (this._propertyAnimation)._propertyResetCallback((this._propertyAnimation)._originalValue); - // } - // } - // if (finished && this.nextAnimation) { - // this.nextAnimation(); - // } - // } } export class Animation extends common.Animation implements definition.Animation { @@ -105,10 +92,8 @@ export class Animation extends common.Animation implements definition.Animation public play(): Promise { var animationFinishedPromise = super.play(); - this._finishedAnimations = 0; this._cancelledAnimations = 0; - this._iOSAnimationFunction(); return animationFinishedPromise; } @@ -161,11 +146,12 @@ export class Animation extends common.Animation implements definition.Animation } }; - this._iOSAnimationFunction = Animation._createiOSAnimationFunction(this._mergedPropertyAnimations, 0, this._playSequentially, animationFinishedCallback, this); + this._iOSAnimationFunction = Animation._createiOSAnimationFunction(this._mergedPropertyAnimations, 0, this._playSequentially, animationFinishedCallback); } - private static _createiOSAnimationFunction(propertyAnimations: Array, index: number, playSequentially: boolean, finishedCallback: (cancelled?: boolean) => void, that:Animation): Function { + private static _createiOSAnimationFunction(propertyAnimations: Array, index: number, playSequentially: boolean, finishedCallback: (cancelled?: boolean) => void): Function { return (cancelled?: boolean) => { + if (cancelled && finishedCallback) { trace.write("Animation " + (index - 1).toString() + " was cancelled. Will skip the rest of animations and call finishedCallback(true).", trace.categories.Animation); finishedCallback(cancelled); @@ -173,239 +159,252 @@ export class Animation extends common.Animation implements definition.Animation } var animation = propertyAnimations[index]; - var nativeView = animation.target._nativeView; - var propertyNameToAnimate = animation.property; - var value = animation.value; - var originalValue; - var presentationLayer = nativeView.layer.presentationLayer(); - var tempRotate = animation.target.rotate * Math.PI / 180; - var abs - - switch (animation.property) { - case common.Properties.backgroundColor: - (animation)._originalValue = animation.target.backgroundColor; - (animation)._propertyResetCallback = (value) => { animation.target.backgroundColor = value }; - if (presentationLayer != null) { - if (nativeView instanceof UILabel) { - nativeView.backgroundColor = UIColor.clearColor(); - } - originalValue = presentationLayer.backgroundColor; - } - else { - originalValue = nativeView.layer.backgroundColor; - } - if (nativeView instanceof UILabel) { - originalValue = nativeView.layer.backgroundColor; - nativeView.setValueForKey(UIColor.clearColor(), "backgroundColor"); - } - value = value.CGColor; - break; - case common.Properties.opacity: - (animation)._originalValue = animation.target.opacity; - (animation)._propertyResetCallback = (value) => { animation.target.opacity = value }; - if (presentationLayer != null) { - originalValue = presentationLayer.opacity; - } - else { - originalValue = nativeView.layer.opacity; - } - break; - case common.Properties.rotate: - (animation)._originalValue = animation.target.rotate; - (animation)._propertyResetCallback = (value) => { animation.target.rotate = value }; - propertyNameToAnimate = "transform.rotation"; - if (presentationLayer != null) { - originalValue = presentationLayer.valueForKeyPath("transform.rotation"); - } - else { - originalValue = nativeView.layer.valueForKeyPath("transform.rotation"); - } - value = value * Math.PI / 180; - abs = fabs(originalValue - value); - if (abs < 0.001 && originalValue !== tempRotate) { - originalValue = tempRotate; - } - break; - case common.Properties.translate: - (animation)._originalValue = { x:animation.target.translateX, y:animation.target.translateY }; - (animation)._propertyResetCallback = (value) => { animation.target.translateX = value.x; animation.target.translateY = value.y; }; - propertyNameToAnimate = "transform" - if (presentationLayer != null) { - originalValue = NSValue.valueWithCATransform3D(presentationLayer.transform); - } - else { - originalValue = NSValue.valueWithCATransform3D(nativeView.layer.transform); - } - value = NSValue.valueWithCATransform3D(CATransform3DTranslate(nativeView.layer.transform, value.x, value.y, 0)); - break; - case common.Properties.scale: - (animation)._originalValue = { x:animation.target.scaleX, y:animation.target.scaleY }; - (animation)._propertyResetCallback = (value) => { animation.target.scaleX = value.x; animation.target.scaleY = value.y; }; - propertyNameToAnimate = "transform" - if (presentationLayer != null) { - originalValue = NSValue.valueWithCATransform3D(presentationLayer.transform); - } - else { - originalValue = NSValue.valueWithCATransform3D(nativeView.layer.transform); - } - value = NSValue.valueWithCATransform3D(CATransform3DScale(nativeView.layer.transform, value.x, value.y, 1)); - break; - case _transform: - if (presentationLayer != null) { - originalValue = NSValue.valueWithCATransform3D(presentationLayer.transform); - } - else { - originalValue = NSValue.valueWithCATransform3D(nativeView.layer.transform); - } - (animation)._originalValue = { xs:animation.target.scaleX, ys:animation.target.scaleY, - xt:animation.target.translateX, yt:animation.target.translateY }; - (animation)._propertyResetCallback = (value) => { - animation.target.translateX = value.xt; - animation.target.translateY = value.yt; - animation.target.scaleX = value.xs; - animation.target.scaleY = value.ys; - }; - propertyNameToAnimate = "transform" - value = NSValue.valueWithCATransform3D(Animation._createNativeAffineTransform(animation)); - break; - default: - throw new Error("Cannot animate " + animation.property); - } - - var nativeAnimation; - var isSpring = false; + var args = Animation._getNativeAnimationArguments(animation); if (animation.curve === enums.AnimationCurve.spring) { - - // nativeAnimation = CASpringAnimation.animationWithKeyPath(propertyNameToAnimate); - // nativeAnimation.duration = nativeAnimation.settlingDuration; - // nativeAnimation.damping = 3; - - var duration = 0.3; - if (animation.duration !== undefined) { - duration = animation.duration / 1000.0; - } - var delay = 0; - if (animation.delay !== undefined) { - delay = CACurrentMediaTime() + (animation.delay / 1000.0); - } - - var callback = undefined; - var nextAnimation; - if (index + 1 < propertyAnimations.length) { - callback = Animation._createiOSAnimationFunction(propertyAnimations, index + 1, playSequentially, finishedCallback, that); - if (!playSequentially) { - callback(); - } - else { - nextAnimation = callback; - } - } - - UIView.animateWithDurationDelayUsingSpringWithDampingInitialSpringVelocityOptionsAnimationsCompletion(duration, delay, 0.2, 0, - UIViewKeyframeAnimationOptions.UIViewKeyframeAnimationOptionCalculationModeLinear, - () => { - if (animation.iterations !== undefined) { - if (animation.iterations === Number.POSITIVE_INFINITY) { - UIView.setAnimationRepeatCount(FLT_MAX); - } - else { - UIView.setAnimationRepeatCount(animation.iterations - 1); - } - } - - switch (animation.property) { - case common.Properties.backgroundColor: - animation.target.backgroundColor = value; - break; - case common.Properties.opacity: - animation.target.opacity = value; - break; - case common.Properties.rotate: - nativeView.layer.setValueForKey(value, propertyNameToAnimate); - break; - case _transform: - (animation)._originalValue = nativeView.layer.transform; - nativeView.layer.setValueForKey(value, propertyNameToAnimate); - (animation)._propertyResetCallback = function (value) { - nativeView.layer.transform = value; - } - break; - } - - }, function (finished:boolean) { - if (finished) { - if (animation.property === _transform) { - if (animation.value[common.Properties.translate] !== undefined) { - animation.target.translateX = animation.value[common.Properties.translate].x; - animation.target.translateY = animation.value[common.Properties.translate].y; - } - if (animation.value[common.Properties.scale] !== undefined) { - animation.target.scaleX = animation.value[common.Properties.scale].x; - animation.target.scaleY = animation.value[common.Properties.scale].y; - } - } - } - else { - if ((animation)._propertyResetCallback) { - (animation)._propertyResetCallback((animation)._originalValue); - } - } - if (finishedCallback) { - var cancelled = !finished; - finishedCallback(cancelled); - } - if (finished && nextAnimation) { - nextAnimation(); - } - }); - - return; + Animation._createNativeSpringAnimation(propertyAnimations, index, playSequentially, args, animation, finishedCallback); } else { - nativeAnimation = CABasicAnimation.animationWithKeyPath(propertyNameToAnimate); - } - nativeAnimation.fromValue = originalValue; - nativeAnimation.toValue = value; - if (animation.duration !== undefined) { - nativeAnimation.duration = animation.duration / 1000.0; - } - else { - nativeAnimation.duration = 0.3; - } - if (animation.delay !== undefined) { - nativeAnimation.beginTime = CACurrentMediaTime() + (animation.delay / 1000.0); + Animation._createNativeAnimation(propertyAnimations, index, playSequentially, args, animation, finishedCallback); } + } + } - if (animation.iterations !== undefined) { - if (animation.iterations === Number.POSITIVE_INFINITY) { - nativeAnimation.repeatCount = FLT_MAX; - } - else { - nativeAnimation.repeatCount = animation.iterations - 1; - } - } - if (!isSpring && animation.curve !== undefined) { - trace.write("The animation curve is " + animation.curve, trace.categories.Animation); - nativeAnimation.timingFunction = animation.curve; - } + private static _getNativeAnimationArguments(animation: common.PropertyAnimation): AnimationInfo { - var animationDelegate: AnimationDelegateImpl = AnimationDelegateImpl.initWithFinishedCallback(finishedCallback, animation); - nativeAnimation.setValueForKey(animationDelegate, "delegate"); + var nativeView = animation.target._nativeView; + var presentationLayer = nativeView.layer.presentationLayer(); + var propertyNameToAnimate = animation.property; + var value = animation.value; + var originalValue; - nativeView.layer.addAnimationForKey(nativeAnimation, propertyNameToAnimate); + var tempRotate = animation.target.rotate * Math.PI / 180; + var abs - var callback = undefined; - if (index+1 < propertyAnimations.length) { - callback = Animation._createiOSAnimationFunction(propertyAnimations, index+1, playSequentially, finishedCallback, that); - if (!playSequentially) { - callback(); - } - else { - animationDelegate.nextAnimation = callback; - } + switch (animation.property) { + case common.Properties.backgroundColor: + (animation)._originalValue = animation.target.backgroundColor; + (animation)._propertyResetCallback = (value) => { animation.target.backgroundColor = value }; + if (presentationLayer != null) { + originalValue = presentationLayer.backgroundColor; + } + else { + originalValue = nativeView.layer.backgroundColor; + } + if (nativeView instanceof UILabel) { + originalValue = nativeView.layer.backgroundColor; + nativeView.setValueForKey(UIColor.clearColor(), "backgroundColor"); + } + value = value.CGColor; + break; + case common.Properties.opacity: + (animation)._originalValue = animation.target.opacity; + (animation)._propertyResetCallback = (value) => { animation.target.opacity = value }; + if (presentationLayer != null) { + originalValue = presentationLayer.opacity; + } + else { + originalValue = nativeView.layer.opacity; + } + break; + case common.Properties.rotate: + (animation)._originalValue = animation.target.rotate; + (animation)._propertyResetCallback = (value) => { animation.target.rotate = value }; + propertyNameToAnimate = "transform.rotation"; + if (presentationLayer != null) { + originalValue = presentationLayer.valueForKeyPath("transform.rotation"); + } + else { + originalValue = nativeView.layer.valueForKeyPath("transform.rotation"); + } + value = value * Math.PI / 180; + abs = fabs(originalValue - value); + if (abs < 0.001 && originalValue !== tempRotate) { + originalValue = tempRotate; + } + break; + case common.Properties.translate: + (animation)._originalValue = { x:animation.target.translateX, y:animation.target.translateY }; + (animation)._propertyResetCallback = (value) => { animation.target.translateX = value.x; animation.target.translateY = value.y; }; + propertyNameToAnimate = "transform" + if (presentationLayer != null) { + originalValue = NSValue.valueWithCATransform3D(presentationLayer.transform); + } + else { + originalValue = NSValue.valueWithCATransform3D(nativeView.layer.transform); + } + value = NSValue.valueWithCATransform3D(CATransform3DTranslate(nativeView.layer.transform, value.x, value.y, 0)); + break; + case common.Properties.scale: + (animation)._originalValue = { x:animation.target.scaleX, y:animation.target.scaleY }; + (animation)._propertyResetCallback = (value) => { animation.target.scaleX = value.x; animation.target.scaleY = value.y; }; + propertyNameToAnimate = "transform" + if (presentationLayer != null) { + originalValue = NSValue.valueWithCATransform3D(presentationLayer.transform); + } + else { + originalValue = NSValue.valueWithCATransform3D(nativeView.layer.transform); + } + value = NSValue.valueWithCATransform3D(CATransform3DScale(nativeView.layer.transform, value.x, value.y, 1)); + break; + case _transform: + if (presentationLayer != null) { + originalValue = NSValue.valueWithCATransform3D(presentationLayer.transform); + } + else { + originalValue = NSValue.valueWithCATransform3D(nativeView.layer.transform); + } + (animation)._originalValue = { xs:animation.target.scaleX, ys:animation.target.scaleY, + xt:animation.target.translateX, yt:animation.target.translateY }; + (animation)._propertyResetCallback = (value) => { + animation.target.translateX = value.xt; + animation.target.translateY = value.yt; + animation.target.scaleX = value.xs; + animation.target.scaleY = value.ys; + }; + propertyNameToAnimate = "transform" + value = NSValue.valueWithCATransform3D(Animation._createNativeAffineTransform(animation)); + break; + default: + throw new Error("Cannot animate " + animation.property); + } + + var duration = 0.3; + if (animation.duration !== undefined) { + duration = animation.duration / 1000.0; + } + + var delay = undefined; + if (animation.delay) { + delay = animation.delay / 1000.0; + } + + var repeatCount = undefined; + if (animation.iterations !== undefined) { + if (animation.iterations === Number.POSITIVE_INFINITY) { + repeatCount = FLT_MAX; + } + else { + repeatCount = animation.iterations - 1; } } + + return { + propertyNameToAnimate: propertyNameToAnimate, + fromValue: originalValue, + toValue: value, + duration: duration, + repeatCount: repeatCount, + delay: delay + }; + } + + private static _createNativeAnimation(propertyAnimations: Array, index: number, playSequentially: boolean, args: AnimationInfo, animation: common.PropertyAnimation, finishedCallback: (cancelled?: boolean) => void) { + + var nativeView = animation.target._nativeView; + var nativeAnimation = CABasicAnimation.animationWithKeyPath(args.propertyNameToAnimate); + nativeAnimation.fromValue = args.fromValue; + nativeAnimation.toValue = args.toValue; + nativeAnimation.duration = args.duration; + if (args.repeatCount !== undefined) { + nativeAnimation.repeatCount = args.repeatCount; + } + if (args.delay !== undefined) { + nativeAnimation.beginTime = CACurrentMediaTime() + args.delay; + } + if (animation.curve !== undefined) { + nativeAnimation.timingFunction = animation.curve; + } + + var animationDelegate = AnimationDelegateImpl.initWithFinishedCallback(finishedCallback, animation); + nativeAnimation.setValueForKey(animationDelegate, "delegate"); + + nativeView.layer.addAnimationForKey(nativeAnimation, args.propertyNameToAnimate); + + var callback = undefined; + if (index+1 < propertyAnimations.length) { + callback = Animation._createiOSAnimationFunction(propertyAnimations, index+1, playSequentially, finishedCallback); + if (!playSequentially) { + callback(); + } + else { + animationDelegate.nextAnimation = callback; + } + } + } + + private static _createNativeSpringAnimation(propertyAnimations: Array, index: number, playSequentially: boolean, args: AnimationInfo, animation: common.PropertyAnimation, finishedCallback: (cancelled?: boolean) => void) { + + var nativeView = animation.target._nativeView; + + var callback = undefined; + var nextAnimation; + if (index + 1 < propertyAnimations.length) { + callback = Animation._createiOSAnimationFunction(propertyAnimations, index + 1, playSequentially, finishedCallback); + if (!playSequentially) { + callback(); + } + else { + nextAnimation = callback; + } + } + + var delay = 0; + if (args.delay) { + delay = args.delay; + } + + UIView.animateWithDurationDelayUsingSpringWithDampingInitialSpringVelocityOptionsAnimationsCompletion(args.duration, delay, 0.2, 0, + UIViewKeyframeAnimationOptions.UIViewKeyframeAnimationOptionCalculationModeLinear, + () => { + if (args.repeatCount !== undefined) { + UIView.setAnimationRepeatCount(args.repeatCount); + } + + switch (animation.property) { + case common.Properties.backgroundColor: + animation.target.backgroundColor = args.toValue; + break; + case common.Properties.opacity: + animation.target.opacity = args.toValue; + break; + case common.Properties.rotate: + nativeView.layer.setValueForKey(args.toValue, args.propertyNameToAnimate); + break; + case _transform: + (animation)._originalValue = nativeView.layer.transform; + nativeView.layer.setValueForKey(args.toValue, args.propertyNameToAnimate); + (animation)._propertyResetCallback = function (value) { + nativeView.layer.transform = value; + } + break; + } + }, function (finished:boolean) { + if (finished) { + if (animation.property === _transform) { + if (animation.value[common.Properties.translate] !== undefined) { + animation.target.translateX = animation.value[common.Properties.translate].x; + animation.target.translateY = animation.value[common.Properties.translate].y; + } + if (animation.value[common.Properties.scale] !== undefined) { + animation.target.scaleX = animation.value[common.Properties.scale].x; + animation.target.scaleY = animation.value[common.Properties.scale].y; + } + } + } + else { + if ((animation)._propertyResetCallback) { + (animation)._propertyResetCallback((animation)._originalValue); + } + } + if (finishedCallback) { + var cancelled = !finished; + finishedCallback(cancelled); + } + if (finished && nextAnimation) { + nextAnimation(); + } + }); } private static _createNativeAffineTransform(animation: common.PropertyAnimation): CATransform3D { From 7b440c822f43b774222c4c98eeb33de339e081b7 Mon Sep 17 00:00:00 2001 From: Tsvetan Raikov Date: Wed, 10 Feb 2016 11:35:03 +0200 Subject: [PATCH 4/5] Updated the animations API --- ui/animation/animation-common.ts | 2 +- ui/animation/animation.android.ts | 6 +++--- ui/animation/animation.d.ts | 2 +- ui/animation/animation.ios.ts | 4 ++-- ui/enums/enums.d.ts | 8 ++++++++ ui/enums/enums.ts | 7 ++++++- 6 files changed, 21 insertions(+), 8 deletions(-) diff --git a/ui/animation/animation-common.ts b/ui/animation/animation-common.ts index 18d68880c..5a461e57c 100644 --- a/ui/animation/animation-common.ts +++ b/ui/animation/animation-common.ts @@ -27,7 +27,7 @@ export interface PropertyAnimation { curve?: any; } -export class CustomAnimationCurve implements definition.CustomAnimationCurve { +export class CubicBezierAnimationCurve implements definition.CubicBezierAnimationCurve { public x1: number; public y1: number; diff --git a/ui/animation/animation.android.ts b/ui/animation/animation.android.ts index 1ef913d9b..b669327d3 100644 --- a/ui/animation/animation.android.ts +++ b/ui/animation/animation.android.ts @@ -327,9 +327,9 @@ export function _resolveAnimationCurve(curve: any): any { return bounce; default: trace.write("Animation curve resolved to original: " + curve, trace.categories.Animation); - if (curve instanceof common.CustomAnimationCurve) { - var animationCurve = curve; - var interpolator = (((android.support.v4.view).animation).PathInterpolatorCompat).create(animationCurve.x1, animationCurve.y1, animationCurve.x2, animationCurve.y2); + if (curve instanceof common.CubicBezierAnimationCurve) { + var animationCurve = curve; + var interpolator = (android).support.v4.view.animation.PathInterpolatorCompat.create(animationCurve.x1, animationCurve.y1, animationCurve.x2, animationCurve.y2); return interpolator; } return curve; diff --git a/ui/animation/animation.d.ts b/ui/animation/animation.d.ts index 7349ca98d..cfc7e1ddf 100644 --- a/ui/animation/animation.d.ts +++ b/ui/animation/animation.d.ts @@ -64,7 +64,7 @@ * Defines a custom animation timing curve by using the cubic-bezier function. * Possible values are numeric values from 0 to 1 */ - export class CustomAnimationCurve { + export class CubicBezierAnimationCurve { public x1: number; public y1: number; diff --git a/ui/animation/animation.ios.ts b/ui/animation/animation.ios.ts index c565740f6..3b9736eb6 100644 --- a/ui/animation/animation.ios.ts +++ b/ui/animation/animation.ios.ts @@ -517,8 +517,8 @@ export function _resolveAnimationCurve(curve: any): any { if (curve instanceof CAMediaTimingFunction) { return curve; } - else if (curve instanceof common.CustomAnimationCurve) { - var animationCurve = curve; + else if (curve instanceof common.CubicBezierAnimationCurve) { + var animationCurve = curve; return CAMediaTimingFunction.functionWithControlPoints(animationCurve.x1, animationCurve.y1, animationCurve.x2, animationCurve.y2); } return undefined; diff --git a/ui/enums/enums.d.ts b/ui/enums/enums.d.ts index bbaa19bcd..a800d2fd9 100644 --- a/ui/enums/enums.d.ts +++ b/ui/enums/enums.d.ts @@ -1,5 +1,7 @@ declare module "ui/enums" { + import animationModule = require("ui/animation"); + /** * Represents a soft keyboard flavor. */ @@ -522,6 +524,7 @@ * Represents an animation curve type. */ module AnimationCurve { + /** * An ease-in curve causes the animation to begin slowly, and then speed up as it progresses. */ @@ -546,5 +549,10 @@ * A spring animation curve causes an animation to produce a spring (bounce) effect. */ export var spring: string; + + /** + * A custom cubic bezier function defined by its two control points. Possible values are numeric values from 0 to 1 + */ + export function cubicBezier(x1: number, y1: number, x2: number, y2: number): animationModule.CubicBezierAnimationCurve; } } diff --git a/ui/enums/enums.ts b/ui/enums/enums.ts index 52cd0e4b5..09c974880 100644 --- a/ui/enums/enums.ts +++ b/ui/enums/enums.ts @@ -1,4 +1,6 @@ -export module KeyboardType { +import animationModule = require("ui/animation"); + +export module KeyboardType { export var datetime = "datetime"; export var phone = "phone"; export var number = "number"; @@ -163,4 +165,7 @@ export module AnimationCurve { export var easeInOut = "easeInOut"; export var linear = "linear"; export var spring = "spring"; + export function cubicBezier(x1: number, y1: number, x2: number, y2: number): animationModule.CubicBezierAnimationCurve { + return new animationModule.CubicBezierAnimationCurve(x1, y1 ,x2, y2); + } } From 796501efcf53a6cd7d34d86bd6568bc35200e7cb Mon Sep 17 00:00:00 2001 From: Tsvetan Raikov Date: Wed, 10 Feb 2016 11:48:43 +0200 Subject: [PATCH 5/5] Fixed tslint issues --- ui/animation/animation.d.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ui/animation/animation.d.ts b/ui/animation/animation.d.ts index cfc7e1ddf..a8d4925ce 100644 --- a/ui/animation/animation.d.ts +++ b/ui/animation/animation.d.ts @@ -61,9 +61,9 @@ } /** - * Defines a custom animation timing curve by using the cubic-bezier function. - * Possible values are numeric values from 0 to 1 - */ + * Defines a custom animation timing curve by using the cubic-bezier function. + * Possible values are numeric values from 0 to 1 + */ export class CubicBezierAnimationCurve { public x1: number;