Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 26 additions & 1 deletion packages/core/ui/animation/animation-common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,9 +139,23 @@ export abstract class AnimationBase {
if ((item === Properties.opacity || item === 'duration' || item === 'delay' || item === 'iterations') && typeof value !== 'number') {
console.error(`Property ${item} must be valid number. Value: ${value}`);
return;
} else if ((item === Properties.scale || item === Properties.translate) && (typeof (<Pair>value).x !== 'number' || typeof (<Pair>value).y !== 'number')) {
} else if (item === Properties.scale && (typeof (<Pair>value).x !== 'number' || typeof (<Pair>value).y !== 'number')) {
console.error(`Property ${item} must be valid Pair. Value: ${value}`);
return;
} else if (item === Properties.translate) {
// Coerce input into PercentLength values so that percentage
// translates (e.g. from keyframe transforms) are preserved.
try {
const x = PercentLength.parse((<any>value).x);
const y = PercentLength.parse((<any>value).y);
if (!isValidTranslateValue(x) || !isValidTranslateValue(y)) {
throw new Error();
}
animationDefinition[item] = { x, y };
} catch {
console.error(`Property ${item} must be valid Pair. Value: ${value}`);
return;
}
} else if (item === Properties.backgroundColor && !Color.isValid(animationDefinition.backgroundColor)) {
console.error(`Property ${item} must be valid color. Value: ${value}`);
return;
Expand Down Expand Up @@ -277,3 +291,14 @@ export abstract class AnimationBase {
});
}
}

function isValidTranslateValue(value: any): boolean {
if (typeof value === 'number') {
return true;
}
if (!value || typeof value !== 'object') {
return false;
}

return (value.unit === 'px' || value.unit === 'dip' || value.unit === '%') && typeof value.value === 'number';
}
11 changes: 8 additions & 3 deletions packages/core/ui/animation/animation-shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export type Transformation = {

export type TransformationType = 'rotate' | 'rotate3d' | 'rotateX' | 'rotateY' | 'translate' | 'translate3d' | 'translateX' | 'translateY' | 'scale' | 'scale3d' | 'scaleX' | 'scaleY';

export type TransformationValue = Point3D | Pair | number;
export type TransformationValue = Point3D | Pair | TranslatePair | number;

export interface Point3D {
x: number;
Expand All @@ -21,7 +21,7 @@ export interface Point3D {
}

export type TransformFunctionsInfo = {
translate: Pair;
translate: TranslatePair;
rotate: Point3D;
scale: Pair;
};
Expand All @@ -31,6 +31,11 @@ export interface Pair {
y: number;
}

export interface TranslatePair {
x: CoreTypes.PercentLengthType;
y: CoreTypes.PercentLengthType;
}

export interface Cancelable {
cancel(): void;
}
Expand All @@ -41,7 +46,7 @@ export interface AnimationDefinition {
target?: View;
opacity?: number;
backgroundColor?: Color | any;
translate?: Pair | { x: number; y: number };
translate?: TranslatePair;
scale?: Pair | { x: number; y: number };
height?: CoreTypes.PercentLengthType | string | any;
width?: CoreTypes.PercentLengthType | string | any;
Expand Down
2 changes: 1 addition & 1 deletion packages/core/ui/animation/index.android.ts
Original file line number Diff line number Diff line change
Expand Up @@ -369,7 +369,7 @@ export class Animation extends AnimationBase {
}
});

animators.push(createAnimationSet([createObjectAnimator(nativeView, 'translationX', propertyAnimation.value.x * density), createObjectAnimator(nativeView, 'translationY', propertyAnimation.value.y * density)], propertyAnimation.iterations));
animators.push(createAnimationSet([createObjectAnimator(nativeView, 'translationX', PercentLength.toDevicePixels(propertyAnimation.value.x, 0, nativeView.getWidth())), createObjectAnimator(nativeView, 'translationY', PercentLength.toDevicePixels(propertyAnimation.value.y, 0, nativeView.getHeight()))], propertyAnimation.iterations));
break;

case Properties.scale:
Expand Down
2 changes: 1 addition & 1 deletion packages/core/ui/animation/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export type { Pair, Transformation, TransformationType, TransformationValue, TransformFunctionsInfo, Point3D, AnimationPromise, Cancelable } from './animation-types';
export type { Pair, TranslatePair, Transformation, TransformationType, TransformationValue, TransformFunctionsInfo, Point3D, AnimationPromise, Cancelable } from './animation-types';
export { KeyframeAnimation, KeyframeAnimationInfo, KeyframeDeclaration, KeyframeInfo } from './keyframe-animation';
import type { AnimationDefinition, AnimationPromise } from './animation-types';

Expand Down
11 changes: 7 additions & 4 deletions packages/core/ui/animation/index.ios.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { View } from '../core/view';
import { CubicBezierAnimationCurve } from '../../core-types/animation-types';
import { Trace } from '../../trace';
import { opacityProperty, backgroundColorProperty, rotateProperty, rotateXProperty, rotateYProperty, translateXProperty, translateYProperty, scaleXProperty, scaleYProperty, heightProperty, widthProperty } from '../styling/style-properties';
import { resolveTranslate } from '../styling/css-transform';
import { PercentLength } from '../styling/length-shared';
import { ios as iosBackground } from '../styling/background';
import { ios as iosViewUtils, NativeScriptUIView } from '../utils';
Expand Down Expand Up @@ -385,7 +386,7 @@ export class Animation extends AnimationBase {
};
propertyNameToAnimate = 'transform';
fromValue = NSValue.valueWithCATransform3D(nativeView.layer.transform);
toValue = NSValue.valueWithCATransform3D(CATransform3DTranslate(nativeView.layer.transform, toValue.x, toValue.y, 0));
toValue = NSValue.valueWithCATransform3D(CATransform3DTranslate(nativeView.layer.transform, resolveTranslate(toValue.x, nativeView.bounds.size.width), resolveTranslate(toValue.y, nativeView.bounds.size.height), 0));
break;
case Properties.scale:
if (toValue.x === 0) {
Expand Down Expand Up @@ -670,8 +671,9 @@ export class Animation extends AnimationBase {
let result: CATransform3D = CATransform3DIdentity;

if (value[Properties.translate] !== undefined) {
const x = value[Properties.translate].x;
const y = value[Properties.translate].y;
const bounds = animation.target.nativeViewProtected ? animation.target.nativeViewProtected.bounds.size : { width: 0, height: 0 };
const x = resolveTranslate(value[Properties.translate].x, bounds.width);
const y = resolveTranslate(value[Properties.translate].y, bounds.height);
result = CATransform3DTranslate(result, x, y, 0);
}

Expand Down Expand Up @@ -957,7 +959,8 @@ function calculateTransform(view: View): CATransform3D {
expectedTransform.m34 = -1 / perspective;
}

expectedTransform = CATransform3DTranslate(expectedTransform, view.translateX, view.translateY, 0);
const bounds = view.nativeViewProtected ? view.nativeViewProtected.bounds.size : { width: 0, height: 0 };
expectedTransform = CATransform3DTranslate(expectedTransform, resolveTranslate(view.translateX, bounds.width), resolveTranslate(view.translateY, bounds.height), 0);
expectedTransform = iosHelper.applyRotateTransform(expectedTransform, view.rotateX, view.rotateY, view.rotate);
expectedTransform = CATransform3DScale(expectedTransform, scaleX, scaleY, 1);

Expand Down
2 changes: 1 addition & 1 deletion packages/core/ui/animation/keyframe-animation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export class KeyframeAnimationInfo {
interface Keyframe {
backgroundColor?: Color;
scale?: { x: number; y: number };
translate?: { x: number; y: number };
translate?: { x: CoreTypes.PercentLengthType; y: CoreTypes.PercentLengthType };
rotate?: { x: number; y: number; z: number };
opacity?: number;
width?: CoreTypes.PercentLengthType;
Expand Down
23 changes: 17 additions & 6 deletions packages/core/ui/core/view/index.android.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import { isCssWideKeyword } from '../properties/property-shared';
import { EventData } from '../../../data/observable';

import { perspectiveProperty, visibilityProperty, opacityProperty, horizontalAlignmentProperty, verticalAlignmentProperty, minWidthProperty, minHeightProperty, maxWidthProperty, maxHeightProperty, widthProperty, heightProperty, marginLeftProperty, marginTopProperty, marginRightProperty, marginBottomProperty, rotateProperty, rotateXProperty, rotateYProperty, scaleXProperty, scaleYProperty, translateXProperty, translateYProperty, zIndexProperty, backgroundInternalProperty, androidElevationProperty, androidDynamicElevationOffsetProperty } from '../../styling/style-properties';
import { isPercentTranslate } from '../../styling/css-transform';
import { PercentLength } from '../../styling/length-shared';
import { CoreTypes } from '../../../core-types';

import { Background, BackgroundClearFlags, refreshBorderDrawable } from '../../styling/background';
Expand Down Expand Up @@ -916,8 +918,17 @@ export class View extends ViewCommon {
}

public layoutNativeView(left: number, top: number, right: number, bottom: number): void {
if (this.nativeViewProtected) {
this.nativeViewProtected.layout(left, top, right, bottom);
const nativeView = this.nativeViewProtected;
if (nativeView) {
nativeView.layout(left, top, right, bottom);

// Percentage translates are resolved against the view's own size.
if (isPercentTranslate(this.translateX)) {
org.nativescript.widgets.ViewHelper.setTranslateX(nativeView, PercentLength.toDevicePixels(this.translateX, 0, nativeView.getWidth()));
}
if (isPercentTranslate(this.translateY)) {
org.nativescript.widgets.ViewHelper.setTranslateY(nativeView, PercentLength.toDevicePixels(this.translateY, 0, nativeView.getHeight()));
}
}
}

Expand Down Expand Up @@ -1581,12 +1592,12 @@ export class View extends ViewCommon {
org.nativescript.widgets.ViewHelper.setScaleY(this.nativeViewProtected, float(value));
}

[translateXProperty.setNative](value: CoreTypes.dip) {
org.nativescript.widgets.ViewHelper.setTranslateX(this.nativeViewProtected, layout.toDevicePixels(value));
[translateXProperty.setNative](value: CoreTypes.PercentLengthType) {
org.nativescript.widgets.ViewHelper.setTranslateX(this.nativeViewProtected, PercentLength.toDevicePixels(value, 0, this.nativeViewProtected ? this.nativeViewProtected.getWidth() : 0));
}

[translateYProperty.setNative](value: CoreTypes.dip) {
org.nativescript.widgets.ViewHelper.setTranslateY(this.nativeViewProtected, layout.toDevicePixels(value));
[translateYProperty.setNative](value: CoreTypes.PercentLengthType) {
org.nativescript.widgets.ViewHelper.setTranslateY(this.nativeViewProtected, PercentLength.toDevicePixels(value, 0, this.nativeViewProtected ? this.nativeViewProtected.getHeight() : 0));
}

[zIndexProperty.getDefault](): number {
Expand Down
10 changes: 6 additions & 4 deletions packages/core/ui/core/view/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -549,18 +549,20 @@ export abstract class View extends ViewCommon {
perspective: number;

/**
* Gets or sets the translateX affine transform of the view in device independent pixels.
* Gets or sets the translateX affine transform of the view.
* Percentages are resolved against the view's own width.
*
* @nsProperty
*/
translateX: CoreTypes.dip;
translateX: CoreTypes.PercentLengthType;

/**
* Gets or sets the translateY affine transform of the view in device independent pixels.
* Gets or sets the translateY affine transform of the view.
* Percentages are resolved against the view's own height.
*
* @nsProperty
*/
translateY: CoreTypes.dip;
translateY: CoreTypes.PercentLengthType;

/**
* Gets or sets the scaleX affine transform of the view.
Expand Down
9 changes: 8 additions & 1 deletion packages/core/ui/core/view/index.ios.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { SDK_VERSION, supportsGlass } from '../../../utils/constants';
import { IOSHelper } from './view-helper';
import { ios as iosBackground, Background } from '../../styling/background';
import { perspectiveProperty, visibilityProperty, opacityProperty, rotateProperty, rotateXProperty, rotateYProperty, scaleXProperty, scaleYProperty, translateXProperty, translateYProperty, zIndexProperty, backgroundInternalProperty, directionProperty } from '../../styling/style-properties';
import { isPercentTranslate, resolveTranslate } from '../../styling/css-transform';
import { profile } from '../../../profiling';
import { accessibilityEnabledProperty, accessibilityHiddenProperty, accessibilityHintProperty, accessibilityIdentifierProperty, accessibilityLabelProperty, accessibilityLanguageProperty, accessibilityLiveRegionProperty, accessibilityMediaSessionProperty, accessibilityRoleProperty, accessibilityStateProperty, accessibilityValueProperty, accessibilityIgnoresInvertColorsProperty } from '../../../accessibility/accessibility-properties';
import { IOSPostAccessibilityNotificationType, AccessibilityEventOptions, AccessibilityRole, AccessibilityState } from '../../../accessibility';
Expand Down Expand Up @@ -424,6 +425,11 @@ export class View extends ViewCommon {
if (this._nativeBackgroundState === 'invalid' || (this._nativeBackgroundState === 'drawn' && backgroundDependsOnSize)) {
this._redrawNativeBackground(background);
}

// Percentage translates are resolved against the view's own size.
if (isPercentTranslate(this.translateX) || isPercentTranslate(this.translateY)) {
this.updateNativeTransform();
}
}

public updateNativeTransform() {
Expand All @@ -439,7 +445,8 @@ export class View extends ViewCommon {
transform.m34 = -1 / perspective;
}

transform = CATransform3DTranslate(transform, this.translateX, this.translateY, 0);
const bounds = nativeView.bounds.size;
transform = CATransform3DTranslate(transform, resolveTranslate(this.translateX, bounds.width), resolveTranslate(this.translateY, bounds.height), 0);
transform = iosUtils.applyRotateTransform(transform, this.rotateX, this.rotateY, this.rotate);
transform = CATransform3DScale(transform, scaleX, scaleY, 1);

Expand Down
8 changes: 4 additions & 4 deletions packages/core/ui/core/view/view-common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -981,17 +981,17 @@ export abstract class ViewCommon extends ViewBase {
this.style.textTransform = value;
}

get translateX(): CoreTypes.dip {
get translateX(): CoreTypes.PercentLengthType {
return this.style.translateX;
}
set translateX(value: CoreTypes.dip) {
set translateX(value: CoreTypes.PercentLengthType) {
this.style.translateX = value;
}

get translateY(): CoreTypes.dip {
get translateY(): CoreTypes.PercentLengthType {
return this.style.translateY;
}
set translateY(value: CoreTypes.dip) {
set translateY(value: CoreTypes.PercentLengthType) {
this.style.translateY = value;
}

Expand Down
2 changes: 1 addition & 1 deletion packages/core/ui/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ export { ActionBar, ActionItem, ActionItems, NavigationButton } from './action-b
export { ActivityIndicator } from './activity-indicator';
export { Animation, _resolveAnimationCurve } from './animation';
export { KeyframeAnimation, KeyframeAnimationInfo, KeyframeDeclaration, KeyframeInfo } from './animation/keyframe-animation';
export type { AnimationDefinition, Pair, Transformation, TransformationType, TransformationValue, TransformFunctionsInfo, Point3D, AnimationPromise, Cancelable } from './animation/animation-types';
export type { AnimationDefinition, Pair, TranslatePair, Transformation, TransformationType, TransformationValue, TransformFunctionsInfo, Point3D, AnimationPromise, Cancelable } from './animation/animation-types';
export * from './animation/animation-shared';
export { Builder } from './builder';
export type { LoadOptions } from './builder';
Expand Down
9 changes: 6 additions & 3 deletions packages/core/ui/layouts/liquid-glass-container/index.ios.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { NativeScriptUIView } from '../../utils';
import { supportsGlass } from '../../../utils/constants';
import { GlassEffectType, iosGlassEffectProperty, View } from '../../core/view';
import { resolveTranslate } from '../../styling/css-transform';
import { LiquidGlassContainerCommon } from './liquid-glass-container-common';
import { toUIGlassStyle } from '../liquid-glass';

Expand Down Expand Up @@ -136,13 +137,15 @@ export class LiquidGlassContainer extends LiquidGlassContainerCommon {
for (let i = 0; i < count; i++) {
const child = this.getChildAt(i) as View | undefined;
if (!child) continue;
const tx = child.translateX || 0;
const ty = child.translateY || 0;
if (!tx && !ty) continue;

const native = child.nativeViewProtected as UIView;
if (!native) continue;

const bounds = native.bounds.size;
const tx = resolveTranslate(child.translateX, bounds.width);
const ty = resolveTranslate(child.translateY, bounds.height);
if (!tx && !ty) continue;

// Skip if the child is still animating (unless forced)
if (!force) {
const keys = native.layer.animationKeys ? native.layer.animationKeys() : null;
Expand Down
Loading
Loading