| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 2f0d3b0 commit 85a84ac
8 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -9,6 +9,7 @@ import { AnimationPromise } from "tns-core-modules/ui/animation"; | |||
| 9 | 9 | ||
| 10 | 10 | // >> animation-require | |
| 11 | 11 | import * as animation from "tns-core-modules/ui/animation"; | |
| 12 | + import {PercentLength} from "tns-core-modules/ui/styling/style-properties"; | ||
| 12 | 13 | // << animation-require | |
| 13 | 14 | ||
| 14 | 15 | function prepareTest(): Label { | |
@@ -370,6 +371,65 @@ export function test_AnimateRotate(done) { | |||
| 370 | 371 | }); | |
| 371 | 372 | } | |
| 372 | 373 | ||
| 374 | + // Bad inputs for PercentLength properties | ||
| 375 | + const badPercentLengthInputs: string[] = [ | ||
| 376 | + '-l??%', | ||
| 377 | + 'qre%', | ||
| 378 | + 'undefinedpx', | ||
| 379 | + 'undefined', | ||
| 380 | + '-frog%' | ||
| 381 | + ]; | ||
| 382 | + | ||
| 383 | + export function test_AnimateHeight(done) { | ||
| 384 | + let label = prepareTest(); | ||
| 385 | + | ||
| 386 | + label.animate({ height: 123, duration: 5 }) | ||
| 387 | + .then(() => { | ||
| 388 | + TKUnit.assertEqual(label.height, 123, "label.height"); | ||
| 389 | + assertIOSNativeTransformIsCorrect(label); | ||
| 390 | + done(); | ||
| 391 | + }) | ||
| 392 | + .catch((e) => { | ||
| 393 | + done(e); | ||
| 394 | + }); | ||
| 395 | + } | ||
| 396 | + | ||
| 397 | + export function test_AnimateHeight_ShouldThrow_IfCannotParsePercentLength() { | ||
| 398 | + const label = new Label(); | ||
| 399 | + helper.buildUIAndRunTest(label, (views: Array<viewModule.View>) => { | ||
| 400 | + badPercentLengthInputs.forEach((input: PercentLength) => { | ||
| 401 | + TKUnit.assertThrows(() => { | ||
| 402 | + label.animate({ height: input }); | ||
| 403 | + }, `Setting height to '${input}' should throw.`); | ||
| 404 | + }); | ||
| 405 | + }); | ||
| 406 | + } | ||
| 407 | + | ||
| 408 | + export function test_AnimateWidth(done) { | ||
| 409 | + let label = prepareTest(); | ||
| 410 | + | ||
| 411 | + label.animate({ width: 123, duration: 5 }) | ||
| 412 | + .then(() => { | ||
| 413 | + TKUnit.assertEqual(label.width, 123, "label.width"); | ||
| 414 | + assertIOSNativeTransformIsCorrect(label); | ||
| 415 | + done(); | ||
| 416 | + }) | ||
| 417 | + .catch((e) => { | ||
| 418 | + done(e); | ||
| 419 | + }); | ||
| 420 | + } | ||
| 421 | + | ||
| 422 | + export function test_AnimateWidth_ShouldThrow_IfCannotParsePercentLength() { | ||
| 423 | + const label = new Label(); | ||
| 424 | + helper.buildUIAndRunTest(label, (views: Array<viewModule.View>) => { | ||
| 425 | + badPercentLengthInputs.forEach((input: PercentLength) => { | ||
| 426 | + TKUnit.assertThrows(() => { | ||
| 427 | + label.animate({ width: input }); | ||
| 428 | + }, `Setting width to '${input}' should throw.`); | ||
| 429 | + }); | ||
| 430 | + }); | ||
| 431 | + } | ||
| 432 | + | ||
| 373 | 433 | export function test_AnimateTranslateScaleAndRotateSimultaneously(done) { | |
| 374 | 434 | let label = prepareTest(); | |
| 375 | 435 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,26 +1,28 @@ | |||
| 1 | 1 | // Definitions. | |
| 2 | 2 | import { | |
| 3 | - CubicBezierAnimationCurve as CubicBezierAnimationCurveDefinition, | ||
| 4 | - AnimationPromise as AnimationPromiseDefinition, | ||
| 5 | 3 | Animation as AnimationBaseDefinition, | |
| 6 | 4 | AnimationDefinition, | |
| 5 | + AnimationPromise as AnimationPromiseDefinition, | ||
| 6 | + CubicBezierAnimationCurve as CubicBezierAnimationCurveDefinition, | ||
| 7 | 7 | Pair | |
| 8 | 8 | } from "."; | |
| 9 | - import { View } from "../core/view"; | ||
| 10 | - | ||
| 9 | + import {View} from "../core/view"; | ||
| 11 | 10 | // Types. | |
| 12 | - import { Color } from "../../color"; | ||
| 13 | - import { isEnabled as traceEnabled, write as traceWrite, categories as traceCategories } from "../../trace"; | ||
| 11 | + import {Color} from "../../color"; | ||
| 12 | + import {categories as traceCategories, isEnabled as traceEnabled, write as traceWrite} from "../../trace"; | ||
| 13 | + import {PercentLength} from "../styling/style-properties"; | ||
| 14 | 14 | ||
| 15 | 15 | export { Color, traceEnabled, traceWrite, traceCategories }; | |
| 16 | 16 | export { AnimationPromise } from "."; | |
| 17 | 17 | ||
| 18 | 18 | export module Properties { | |
| 19 | - export var opacity = "opacity"; | ||
| 20 | - export var backgroundColor = "backgroundColor"; | ||
| 21 | - export var translate = "translate"; | ||
| 22 | - export var rotate = "rotate"; | ||
| 23 | - export var scale = "scale"; | ||
| 19 | + export const opacity = "opacity"; | ||
| 20 | + export const backgroundColor = "backgroundColor"; | ||
| 21 | + export const translate = "translate"; | ||
| 22 | + export const rotate = "rotate"; | ||
| 23 | + export const scale = "scale"; | ||
| 24 | + export const height = "height"; | ||
| 25 | + export const width = "width"; | ||
| 24 | 26 | } | |
| 25 | 27 | ||
| 26 | 28 | export interface PropertyAnimation { | |
@@ -163,6 +165,9 @@ export abstract class AnimationBase implements AnimationBaseDefinition { | |||
| 163 | 165 | throw new Error(`Property ${item} must be valid Pair. Value: ${animationDefinition[item]}`); | |
| 164 | 166 | } else if (item === Properties.backgroundColor && !Color.isValid(animationDefinition.backgroundColor)) { | |
| 165 | 167 | throw new Error(`Property ${item} must be valid color. Value: ${animationDefinition[item]}`); | |
| 168 | + } else if (item === Properties.width || item === Properties.height) { | ||
| 169 | + // parse will throw if it sees an invalid value | ||
| 170 | + PercentLength.parse(animationDefinition[item]); | ||
| 166 | 171 | } | |
| 167 | 172 | } | |
| 168 | 173 | ||
@@ -234,8 +239,34 @@ export abstract class AnimationBase implements AnimationBaseDefinition { | |||
| 234 | 239 | }); | |
| 235 | 240 | } | |
| 236 | 241 | ||
| 242 | + // height | ||
| 243 | + if (animationDefinition.height !== undefined) { | ||
| 244 | + propertyAnimations.push({ | ||
| 245 | + target: animationDefinition.target, | ||
| 246 | + property: Properties.height, | ||
| 247 | + value: animationDefinition.height, | ||
| 248 | + duration: animationDefinition.duration, | ||
| 249 | + delay: animationDefinition.delay, | ||
| 250 | + iterations: animationDefinition.iterations, | ||
| 251 | + curve: animationDefinition.curve | ||
| 252 | + }); | ||
| 253 | + } | ||
| 254 | + | ||
| 255 | + // width | ||
| 256 | + if (animationDefinition.width !== undefined) { | ||
| 257 | + propertyAnimations.push({ | ||
| 258 | + target: animationDefinition.target, | ||
| 259 | + property: Properties.width, | ||
| 260 | + value: animationDefinition.width, | ||
| 261 | + duration: animationDefinition.duration, | ||
| 262 | + delay: animationDefinition.delay, | ||
| 263 | + iterations: animationDefinition.iterations, | ||
| 264 | + curve: animationDefinition.curve | ||
| 265 | + }); | ||
| 266 | + } | ||
| 267 | + | ||
| 237 | 268 | if (propertyAnimations.length === 0) { | |
| 238 | - throw new Error("No animation property specified."); | ||
| 269 | + throw new Error('No known animation properties specified'); | ||
| 239 | 270 | } | |
| 240 | 271 | ||
| 241 | 272 | return propertyAnimations; | |
@@ -252,4 +283,4 @@ export abstract class AnimationBase implements AnimationBaseDefinition { | |||
| 252 | 283 | curve: animation.curve | |
| 253 | 284 | }); | |
| 254 | 285 | } | |
| 255 | - } | ||
| 286 | + } | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,15 +1,35 @@ | |||
| 1 | 1 | // Definitions. | |
| 2 | - import { AnimationDefinition } from "."; | ||
| 3 | - import { View } from "../core/view"; | ||
| 2 | + import {AnimationDefinition} from '.'; | ||
| 3 | + import {View} from '../core/view'; | ||
| 4 | 4 | ||
| 5 | - import { AnimationBase, Properties, PropertyAnimation, CubicBezierAnimationCurve, AnimationPromise, Color, traceWrite, traceEnabled, traceCategories } from "./animation-common"; | ||
| 6 | 5 | import { | |
| 7 | - opacityProperty, backgroundColorProperty, rotateProperty, | ||
| 8 | - translateXProperty, translateYProperty, scaleXProperty, scaleYProperty | ||
| 9 | - } from "../styling/style-properties"; | ||
| 10 | - | ||
| 11 | - import { layout } from "../../utils/utils"; | ||
| 12 | - import lazy from "../../utils/lazy"; | ||
| 6 | + AnimationBase, | ||
| 7 | + AnimationPromise, | ||
| 8 | + Color, | ||
| 9 | + CubicBezierAnimationCurve, | ||
| 10 | + Properties, | ||
| 11 | + PropertyAnimation, | ||
| 12 | + traceCategories, | ||
| 13 | + traceEnabled, | ||
| 14 | + traceWrite | ||
| 15 | + } from './animation-common'; | ||
| 16 | + import { | ||
| 17 | + backgroundColorProperty, | ||
| 18 | + heightProperty, | ||
| 19 | + opacityProperty, | ||
| 20 | + PercentLength, | ||
| 21 | + rotateProperty, | ||
| 22 | + scaleXProperty, | ||
| 23 | + scaleYProperty, | ||
| 24 | + translateXProperty, | ||
| 25 | + translateYProperty, | ||
| 26 | + widthProperty | ||
| 27 | + } from '../styling/style-properties'; | ||
| 28 | + | ||
| 29 | + import {layout} from '../../utils/utils'; | ||
| 30 | + import lazy from '../../utils/lazy'; | ||
| 31 | + | ||
| 32 | + import * as platform from '../../platform'; | ||
| 13 | 33 | ||
| 14 | 34 | export * from "./animation-common"; | |
| 15 | 35 | ||
@@ -37,6 +57,8 @@ propertyKeys[Properties.opacity] = Symbol(keyPrefix + Properties.opacity); | |||
| 37 | 57 | propertyKeys[Properties.rotate] = Symbol(keyPrefix + Properties.rotate); | |
| 38 | 58 | propertyKeys[Properties.scale] = Symbol(keyPrefix + Properties.scale); | |
| 39 | 59 | propertyKeys[Properties.translate] = Symbol(keyPrefix + Properties.translate); | |
| 60 | + propertyKeys[Properties.height] = Symbol(keyPrefix + Properties.height); | ||
| 61 | + propertyKeys[Properties.width] = Symbol(keyPrefix + Properties.width); | ||
| 40 | 62 | ||
| 41 | 63 | export function _resolveAnimationCurve(curve: string | CubicBezierAnimationCurve | android.view.animation.Interpolator | android.view.animation.LinearInterpolator): android.view.animation.Interpolator { | |
| 42 | 64 | switch (curve) { | |
@@ -195,7 +217,7 @@ export class Animation extends AnimationBase { | |||
| 195 | 217 | } | |
| 196 | 218 | } | |
| 197 | 219 | ||
| 198 | - private _onAndroidAnimationCancel() { // tslint:disable-line | ||
| 220 | + private _onAndroidAnimationCancel() { // tslint:disable-line | ||
| 199 | 221 | this._propertyResetCallbacks.forEach(v => v()); | |
| 200 | 222 | this._rejectAnimationFinishedPromise(); | |
| 201 | 223 | ||
@@ -301,7 +323,7 @@ export class Animation extends AnimationBase { | |||
| 301 | 323 | } else { | |
| 302 | 324 | propertyAnimation.target.style[backgroundColorProperty.keyframe] = originalValue1; | |
| 303 | 325 | } | |
| 304 | - | ||
| 326 | + | ||
| 305 | 327 | if (propertyAnimation.target.nativeViewProtected && propertyAnimation.target[backgroundColorProperty.setNative]) { | |
| 306 | 328 | propertyAnimation.target[backgroundColorProperty.setNative](propertyAnimation.target.style.backgroundColor); | |
| 307 | 329 | } | |
@@ -414,13 +436,85 @@ export class Animation extends AnimationBase { | |||
| 414 | 436 | } else { | |
| 415 | 437 | propertyAnimation.target.style[rotateProperty.keyframe] = originalValue1; | |
| 416 | 438 | } | |
| 417 | - | ||
| 439 | + | ||
| 418 | 440 | if (propertyAnimation.target.nativeViewProtected) { | |
| 419 | 441 | propertyAnimation.target[rotateProperty.setNative](propertyAnimation.target.style.rotate); | |
| 420 | 442 | } | |
| 421 | 443 | })); | |
| 422 | 444 | animators.push(android.animation.ObjectAnimator.ofFloat(nativeView, "rotation", nativeArray)); | |
| 423 | 445 | break; | |
| 446 | + case Properties.height: | ||
| 447 | + heightProperty._initDefaultNativeValue(style); | ||
| 448 | + nativeArray = Array.create("float", 2); | ||
| 449 | + let toValue = propertyAnimation.value; | ||
| 450 | + let parent = propertyAnimation.target.parent as View; | ||
| 451 | + if (!parent) { | ||
| 452 | + throw new Error('cannot animate height on root view'); | ||
| 453 | + } | ||
| 454 | + const parentHeight: number = parent.getMeasuredHeight(); | ||
| 455 | + toValue = PercentLength.toDevicePixels(toValue, parentHeight, parentHeight) / platform.screen.mainScreen.scale; | ||
| 456 | + let fromValue = originalValue1 = nativeView.getHeight() / platform.screen.mainScreen.scale; | ||
| 457 | + nativeArray[0] = fromValue; | ||
| 458 | + nativeArray[1] = toValue; | ||
| 459 | + let heightAnimator = android.animation.ValueAnimator.ofFloat(nativeArray); | ||
| 460 | + heightAnimator.addUpdateListener(new android.animation.ValueAnimator.AnimatorUpdateListener({ | ||
| 461 | + onAnimationUpdate(animator: android.animation.ValueAnimator) { | ||
| 462 | + let argb = (<java.lang.Float>animator.getAnimatedValue()).floatValue(); | ||
| 463 | + propertyAnimation.target.style[setLocal ? heightProperty.name : heightProperty.keyframe] = argb; | ||
| 464 | + } | ||
| 465 | + })); | ||
| 466 | + propertyUpdateCallbacks.push(checkAnimation(() => { | ||
| 467 | + propertyAnimation.target.style[setLocal ? heightProperty.name : heightProperty.keyframe] = propertyAnimation.value; | ||
| 468 | + })); | ||
| 469 | + propertyResetCallbacks.push(checkAnimation(() => { | ||
| 470 | + if (setLocal) { | ||
| 471 | + propertyAnimation.target.style[heightProperty.name] = originalValue1; | ||
| 472 | + } else { | ||
| 473 | + propertyAnimation.target.style[heightProperty.keyframe] = originalValue1; | ||
| 474 | + } | ||
| 475 | + | ||
| 476 | + if (propertyAnimation.target.nativeViewProtected) { | ||
| 477 | + propertyAnimation.target[heightProperty.setNative](propertyAnimation.target.style.height); | ||
| 478 | + } | ||
| 479 | + })); | ||
| 480 | + animators.push(heightAnimator); | ||
| 481 | + break; | ||
| 482 | + | ||
| 483 | + case Properties.width: | ||
| 484 | + widthProperty._initDefaultNativeValue(style); | ||
| 485 | + nativeArray = Array.create("float", 2); | ||
| 486 | + let toWidthValue = propertyAnimation.value; | ||
| 487 | + let widthParent = propertyAnimation.target.parent as View; | ||
| 488 | + if (!widthParent) { | ||
| 489 | + throw new Error('cannot animate width on root view'); | ||
| 490 | + } | ||
| 491 | + const parentWidth: number = widthParent.getMeasuredWidth(); | ||
| 492 | + toWidthValue = PercentLength.toDevicePixels(toWidthValue, parentWidth, parentWidth) / platform.screen.mainScreen.scale; | ||
| 493 | + originalValue1 = nativeArray[0] = nativeView.getWidth() / platform.screen.mainScreen.scale; | ||
| 494 | + nativeArray[1] = toWidthValue; | ||
| 495 | + let widthAnimator = android.animation.ValueAnimator.ofFloat(nativeArray); | ||
| 496 | + widthAnimator.addUpdateListener(new android.animation.ValueAnimator.AnimatorUpdateListener({ | ||
| 497 | + onAnimationUpdate(animator: android.animation.ValueAnimator) { | ||
| 498 | + let argb = (<java.lang.Float>animator.getAnimatedValue()).floatValue(); | ||
| 499 | + propertyAnimation.target.style[setLocal ? widthProperty.name : widthProperty.keyframe] = argb; | ||
| 500 | + } | ||
| 501 | + })); | ||
| 502 | + propertyUpdateCallbacks.push(checkAnimation(() => { | ||
| 503 | + propertyAnimation.target.style[setLocal ? widthProperty.name : widthProperty.keyframe] = propertyAnimation.value; | ||
| 504 | + })); | ||
| 505 | + propertyResetCallbacks.push(checkAnimation(() => { | ||
| 506 | + if (setLocal) { | ||
| 507 | + propertyAnimation.target.style[widthProperty.name] = originalValue1; | ||
| 508 | + } else { | ||
| 509 | + propertyAnimation.target.style[widthProperty.keyframe] = originalValue1; | ||
| 510 | + } | ||
| 511 | + | ||
| 512 | + if (propertyAnimation.target.nativeViewProtected) { | ||
| 513 | + propertyAnimation.target[widthProperty.setNative](propertyAnimation.target.style.width); | ||
| 514 | + } | ||
| 515 | + })); | ||
| 516 | + animators.push(widthAnimator); | ||
| 517 | + break; | ||
| 424 | 518 | ||
| 425 | 519 | default: | |
| 426 | 520 | throw new Error("Cannot animate " + propertyAnimation.property); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -3,6 +3,7 @@ | |||
| 3 | 3 | */ /** */ | |
| 4 | 4 | ||
| 5 | 5 | import { View, Color } from "../core/view"; | |
| 6 | + import {PercentLength} from '../styling/style-properties'; | ||
| 6 | 7 | ||
| 7 | 8 | /** | |
| 8 | 9 | * Defines animation options for the View.animate method. | |
@@ -33,6 +34,16 @@ export interface AnimationDefinition { | |||
| 33 | 34 | */ | |
| 34 | 35 | scale?: Pair; | |
| 35 | 36 | ||
| 37 | + /** | ||
| 38 | + * Animates the height of a view. | ||
| 39 | + */ | ||
| 40 | + height?: PercentLength; | ||
| 41 | + | ||
| 42 | + /** | ||
| 43 | + * Animates the width of a view. | ||
| 44 | + */ | ||
| 45 | + width?: PercentLength; | ||
| 46 | + | ||
| 36 | 47 | /** | |
| 37 | 48 | * Animates the rotate affine transform of the view. Value should be a number specifying the rotation amount in degrees. | |
| 38 | 49 | */ | |
| Back | FazBrowse Home | New Git URL |
0 commit comments