mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-11-05 13:26:48 +08:00
Merge remote-tracking branch 'origin/main' into refactor/circular-deps
This commit is contained in:
@@ -159,8 +159,8 @@ export function test_ChainingAnimations(done) {
|
||||
.then(() => label.animate({ translate: { x: 0, y: 0 }, duration: duration }))
|
||||
.then(() => label.animate({ scale: { x: 5, y: 5 }, duration: duration }))
|
||||
.then(() => label.animate({ scale: { x: 1, y: 1 }, duration: duration }))
|
||||
.then(() => label.animate({ rotate: { x: 90, y: 0, z: 180 }, duration: duration }))
|
||||
.then(() => label.animate({ rotate: { x: 0, y: 0, z: 0 }, duration: duration }))
|
||||
.then(() => label.animate({ rotate: 180, duration: duration }))
|
||||
.then(() => label.animate({ rotate: 0, duration: duration }))
|
||||
.then(() => {
|
||||
//console.log("Animation finished");
|
||||
// >> (hide)
|
||||
|
||||
@@ -109,16 +109,11 @@ export function testBackgroundInternalChangedOnceOnResize() {
|
||||
|
||||
TKUnit.assertEqual(trackCount(), 1, 'Expected background to be re-applied at most once when the view is laid-out on 0 0 200 200.');
|
||||
|
||||
// Ignore safe area as it may result in re-calculating view frame, thus trigger a size change regardless
|
||||
layout.iosIgnoreSafeArea = true;
|
||||
|
||||
layout.requestLayout();
|
||||
layout.layout(50, 50, 250, 250);
|
||||
|
||||
TKUnit.assertEqual(trackCount(), 0, 'Expected background to NOT change when view is laid-out from 0 0 200 200 to 50 50 250 250.');
|
||||
|
||||
layout.iosIgnoreSafeArea = false;
|
||||
|
||||
layout.requestLayout();
|
||||
layout.layout(0, 0, 250, 250);
|
||||
|
||||
|
||||
Binary file not shown.
@@ -79,8 +79,8 @@ class AnimationDelegateImpl extends NSObject implements CAAnimationDelegate {
|
||||
targetStyle[setLocal ? widthProperty.name : widthProperty.keyframe] = value;
|
||||
break;
|
||||
case Properties.scale:
|
||||
targetStyle[setLocal ? scaleXProperty.name : scaleXProperty.keyframe] = value.x === 0 ? 1e-6 : value.x;
|
||||
targetStyle[setLocal ? scaleYProperty.name : scaleYProperty.keyframe] = value.y === 0 ? 1e-6 : 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) {
|
||||
@@ -95,8 +95,8 @@ class AnimationDelegateImpl extends NSObject implements CAAnimationDelegate {
|
||||
if (value[Properties.scale] !== undefined) {
|
||||
const x = value[Properties.scale].x;
|
||||
const y = value[Properties.scale].y;
|
||||
targetStyle[setLocal ? scaleXProperty.name : scaleXProperty.keyframe] = x === 0 ? 1e-6 : x;
|
||||
targetStyle[setLocal ? scaleYProperty.name : scaleYProperty.keyframe] = y === 0 ? 1e-6 : y;
|
||||
targetStyle[setLocal ? scaleXProperty.name : scaleXProperty.keyframe] = x === 0 ? 0.001 : x;
|
||||
targetStyle[setLocal ? scaleYProperty.name : scaleYProperty.keyframe] = y === 0 ? 0.001 : y;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -309,6 +309,7 @@ export class Animation extends AnimationBase {
|
||||
const parent = view.parent as View;
|
||||
|
||||
let propertyNameToAnimate = animation.property;
|
||||
let subPropertyNameToAnimate;
|
||||
let toValue = animation.value;
|
||||
let fromValue;
|
||||
if (nativeView) {
|
||||
@@ -334,6 +335,8 @@ export class Animation extends AnimationBase {
|
||||
};
|
||||
fromValue = nativeView.layer.opacity;
|
||||
break;
|
||||
// In the case of rotation, avoid animating affine transform directly as it will animate to the closest result
|
||||
// that is visually the same. For example, 0 -> 360 will leave view as is.
|
||||
case Properties.rotate:
|
||||
animation._originalValue = {
|
||||
x: view.rotateX,
|
||||
@@ -346,9 +349,30 @@ export class Animation extends AnimationBase {
|
||||
style[setLocal ? rotateYProperty.name : rotateYProperty.keyframe] = value.y;
|
||||
};
|
||||
|
||||
propertyNameToAnimate = 'transform';
|
||||
fromValue = NSValue.valueWithCATransform3D(nativeView.layer.transform);
|
||||
toValue = NSValue.valueWithCATransform3D(iosHelper.applyRotateTransform(nativeView.layer.transform, toValue.x, toValue.y, toValue.z));
|
||||
propertyNameToAnimate = 'transform.rotation';
|
||||
subPropertyNameToAnimate = ['x', 'y', 'z'];
|
||||
fromValue = {
|
||||
x: nativeView.layer.valueForKeyPath('transform.rotation.x'),
|
||||
y: nativeView.layer.valueForKeyPath('transform.rotation.y'),
|
||||
z: nativeView.layer.valueForKeyPath('transform.rotation.z'),
|
||||
};
|
||||
|
||||
if (animation.target.rotateX !== undefined && animation.target.rotateX !== 0 && Math.floor(toValue / 360) - toValue / 360 === 0) {
|
||||
fromValue.x = (animation.target.rotateX * Math.PI) / 180;
|
||||
}
|
||||
if (animation.target.rotateY !== undefined && animation.target.rotateY !== 0 && Math.floor(toValue / 360) - toValue / 360 === 0) {
|
||||
fromValue.y = (animation.target.rotateY * Math.PI) / 180;
|
||||
}
|
||||
if (animation.target.rotate !== undefined && animation.target.rotate !== 0 && Math.floor(toValue / 360) - toValue / 360 === 0) {
|
||||
fromValue.z = (animation.target.rotate * Math.PI) / 180;
|
||||
}
|
||||
|
||||
// Respect only value.z for back-compat until 3D rotations are implemented
|
||||
toValue = {
|
||||
x: (toValue.x * Math.PI) / 180,
|
||||
y: (toValue.y * Math.PI) / 180,
|
||||
z: (toValue.z * Math.PI) / 180,
|
||||
};
|
||||
break;
|
||||
case Properties.translate:
|
||||
animation._originalValue = {
|
||||
@@ -365,10 +389,10 @@ export class Animation extends AnimationBase {
|
||||
break;
|
||||
case Properties.scale:
|
||||
if (toValue.x === 0) {
|
||||
toValue.x = 1e-6;
|
||||
toValue.x = 0.001;
|
||||
}
|
||||
if (toValue.y === 0) {
|
||||
toValue.y = 1e-6;
|
||||
toValue.y = 0.001;
|
||||
}
|
||||
animation._originalValue = { x: view.scaleX, y: view.scaleY };
|
||||
animation._propertyResetCallback = (value, valueSource) => {
|
||||
@@ -451,6 +475,7 @@ export class Animation extends AnimationBase {
|
||||
return {
|
||||
propertyNameToAnimate: propertyNameToAnimate,
|
||||
fromValue: fromValue,
|
||||
subPropertiesToAnimate: subPropertyNameToAnimate,
|
||||
toValue: toValue,
|
||||
duration: duration,
|
||||
repeatCount: repeatCount,
|
||||
@@ -496,10 +521,10 @@ export class Animation extends AnimationBase {
|
||||
}
|
||||
|
||||
private static _createGroupAnimation(args: AnimationInfo, animation: PropertyAnimation) {
|
||||
const animations = NSMutableArray.alloc<CAAnimation>().initWithCapacity(args.subPropertiesToAnimate.length);
|
||||
const groupAnimation = CAAnimationGroup.new();
|
||||
groupAnimation.duration = args.duration;
|
||||
const animations = NSMutableArray.alloc<CAAnimation>().initWithCapacity(args.subPropertiesToAnimate.length);
|
||||
|
||||
groupAnimation.duration = args.duration;
|
||||
if (args.repeatCount !== undefined) {
|
||||
groupAnimation.repeatCount = args.repeatCount;
|
||||
}
|
||||
@@ -651,30 +676,16 @@ export class Animation extends AnimationBase {
|
||||
}
|
||||
|
||||
if (value[Properties.scale] !== undefined) {
|
||||
const x = value[Properties.scale].x || 1e-6;
|
||||
const y = value[Properties.scale].y || 1e-6;
|
||||
result = CATransform3DScale(result, x, y, 1);
|
||||
}
|
||||
|
||||
if (value[Properties.rotate] !== undefined) {
|
||||
const x = value[Properties.rotate].x;
|
||||
const y = value[Properties.rotate].y;
|
||||
const z = value[Properties.rotate].z;
|
||||
const perspective = animation.target.perspective || 300;
|
||||
|
||||
// Set perspective in case of rotation since we use z
|
||||
if (x || y) {
|
||||
result.m34 = -1 / perspective;
|
||||
}
|
||||
|
||||
result = iosHelper.applyRotateTransform(result, x, y, z);
|
||||
const x = value[Properties.scale].x;
|
||||
const y = value[Properties.scale].y;
|
||||
result = CATransform3DScale(result, x === 0 ? 0.001 : x, y === 0 ? 0.001 : y, 1);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static _isAffineTransform(property: string): boolean {
|
||||
return property === _transform || property === Properties.translate || property === Properties.scale || property === Properties.rotate;
|
||||
return property === _transform || property === Properties.translate || property === Properties.scale;
|
||||
}
|
||||
|
||||
private static _canBeMerged(animation1: PropertyAnimation, animation2: PropertyAnimation) {
|
||||
@@ -941,8 +952,7 @@ function calculateTransform(view: View): CATransform3D {
|
||||
// Order is important: translate, rotate, scale
|
||||
let expectedTransform = new CATransform3D(CATransform3DIdentity);
|
||||
|
||||
// TODO: Add perspective property to transform animations (not just rotation)
|
||||
// Set perspective in case of rotation since we use z
|
||||
// Only set perspective if there is 3D rotation
|
||||
if (view.rotateX || view.rotateY) {
|
||||
expectedTransform.m34 = -1 / perspective;
|
||||
}
|
||||
|
||||
@@ -150,7 +150,7 @@ export class Property<T extends ViewBase, U> implements TypedPropertyDescriptor<
|
||||
public readonly key: symbol;
|
||||
|
||||
public readonly getDefault: symbol;
|
||||
public readonly setNative: any;
|
||||
public readonly setNative: symbol;
|
||||
|
||||
public readonly defaultValueKey: symbol;
|
||||
public readonly defaultValue: U;
|
||||
@@ -351,7 +351,7 @@ export class CoercibleProperty<T extends ViewBase, U> extends Property<T, U> imp
|
||||
const propertyName = options.name;
|
||||
const key = this.key;
|
||||
const getDefault: symbol = this.getDefault;
|
||||
const setNative: any = this.setNative;
|
||||
const setNative: symbol = this.setNative;
|
||||
const defaultValueKey = this.defaultValueKey;
|
||||
const defaultValue: U = this.defaultValue;
|
||||
|
||||
@@ -566,7 +566,7 @@ export class CssProperty<T extends Style, U> {
|
||||
|
||||
public readonly key: symbol;
|
||||
public readonly getDefault: symbol;
|
||||
public readonly setNative: any;
|
||||
public readonly setNative: symbol;
|
||||
public readonly sourceKey: symbol;
|
||||
public readonly defaultValueKey: symbol;
|
||||
public readonly defaultValue: U;
|
||||
@@ -833,7 +833,7 @@ export class CssAnimationProperty<T extends Style, U> implements CssAnimationPro
|
||||
public readonly cssLocalName: string;
|
||||
|
||||
public readonly getDefault: symbol;
|
||||
public readonly setNative: any;
|
||||
public readonly setNative: symbol;
|
||||
|
||||
public readonly register: (cls: { prototype }) => void;
|
||||
|
||||
|
||||
@@ -105,12 +105,13 @@ export interface ShowModalOptions {
|
||||
* @param criterion - The type of ancestor view we are looking for. Could be a string containing a class name or an actual type.
|
||||
* Returns an instance of a view (if found), otherwise undefined.
|
||||
*/
|
||||
export function getAncestor(view: ViewBase, criterion: string | { new () }): ViewBase {
|
||||
let matcher: (view: ViewBase) => boolean = null;
|
||||
export function getAncestor<T extends ViewBase = ViewBase>(view: T, criterion: string | { new () }): T {
|
||||
let matcher: (view: ViewBase) => view is T;
|
||||
|
||||
if (typeof criterion === 'string') {
|
||||
matcher = (view: ViewBase) => view.typeName === criterion;
|
||||
matcher = (view: ViewBase): view is T => view.typeName === criterion;
|
||||
} else {
|
||||
matcher = (view: ViewBase) => view instanceof criterion;
|
||||
matcher = (view: ViewBase): view is T => view instanceof criterion;
|
||||
}
|
||||
|
||||
for (let parent = view.parent; parent != null; parent = parent.parent) {
|
||||
|
||||
@@ -809,6 +809,117 @@ export class View extends ViewCommon {
|
||||
this.nativeViewProtected.setAlpha(float(value));
|
||||
}
|
||||
|
||||
[accessibilityRoleProperty.setNative](value: AccessibilityRole): void {
|
||||
this.accessibilityRole = value as AccessibilityRole;
|
||||
updateA11yPropertiesCallback(this);
|
||||
|
||||
if (SDK_VERSION >= 28) {
|
||||
this.nativeViewProtected?.setAccessibilityHeading(value === AccessibilityRole.Header);
|
||||
}
|
||||
}
|
||||
|
||||
[accessibilityLiveRegionProperty.setNative](value: AccessibilityLiveRegion): void {
|
||||
switch (value as AccessibilityLiveRegion) {
|
||||
case AccessibilityLiveRegion.Assertive: {
|
||||
this.nativeViewProtected.setAccessibilityLiveRegion(android.view.View.ACCESSIBILITY_LIVE_REGION_ASSERTIVE);
|
||||
break;
|
||||
}
|
||||
case AccessibilityLiveRegion.Polite: {
|
||||
this.nativeViewProtected.setAccessibilityLiveRegion(android.view.View.ACCESSIBILITY_LIVE_REGION_POLITE);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
this.nativeViewProtected.setAccessibilityLiveRegion(android.view.View.ACCESSIBILITY_LIVE_REGION_NONE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[accessibilityStateProperty.setNative](value: AccessibilityState): void {
|
||||
this.accessibilityState = value as AccessibilityState;
|
||||
updateA11yPropertiesCallback(this);
|
||||
}
|
||||
|
||||
[horizontalAlignmentProperty.getDefault](): CoreTypes.HorizontalAlignmentType {
|
||||
return <CoreTypes.HorizontalAlignmentType>org.nativescript.widgets.ViewHelper.getHorizontalAlignment(this.nativeViewProtected);
|
||||
}
|
||||
[horizontalAlignmentProperty.setNative](value: CoreTypes.HorizontalAlignmentType) {
|
||||
const nativeView = this.nativeViewProtected;
|
||||
const lp: any = nativeView.getLayoutParams() || new org.nativescript.widgets.CommonLayoutParams();
|
||||
const gravity = lp.gravity;
|
||||
const weight = lp.weight;
|
||||
// Set only if params gravity exists.
|
||||
if (gravity !== undefined) {
|
||||
switch (value) {
|
||||
case 'left':
|
||||
lp.gravity = GRAVITY_LEFT | (gravity & VERTICAL_GRAVITY_MASK);
|
||||
if (weight < 0) {
|
||||
lp.weight = -2;
|
||||
}
|
||||
break;
|
||||
case 'center':
|
||||
lp.gravity = GRAVITY_CENTER_HORIZONTAL | (gravity & VERTICAL_GRAVITY_MASK);
|
||||
if (weight < 0) {
|
||||
lp.weight = -2;
|
||||
}
|
||||
break;
|
||||
case 'right':
|
||||
lp.gravity = GRAVITY_RIGHT | (gravity & VERTICAL_GRAVITY_MASK);
|
||||
if (weight < 0) {
|
||||
lp.weight = -2;
|
||||
}
|
||||
break;
|
||||
case 'stretch':
|
||||
lp.gravity = GRAVITY_FILL_HORIZONTAL | (gravity & VERTICAL_GRAVITY_MASK);
|
||||
if (weight < 0) {
|
||||
lp.weight = -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
nativeView.setLayoutParams(lp);
|
||||
}
|
||||
}
|
||||
|
||||
[verticalAlignmentProperty.getDefault](): CoreTypes.VerticalAlignmentType {
|
||||
return <CoreTypes.VerticalAlignmentType>org.nativescript.widgets.ViewHelper.getVerticalAlignment(this.nativeViewProtected);
|
||||
}
|
||||
[verticalAlignmentProperty.setNative](value: CoreTypes.VerticalAlignmentType) {
|
||||
const nativeView = this.nativeViewProtected;
|
||||
const lp: any = nativeView.getLayoutParams() || new org.nativescript.widgets.CommonLayoutParams();
|
||||
const gravity = lp.gravity;
|
||||
const height = lp.height;
|
||||
// Set only if params gravity exists.
|
||||
if (gravity !== undefined) {
|
||||
switch (value) {
|
||||
case 'top':
|
||||
lp.gravity = GRAVITY_TOP | (gravity & HORIZONTAL_GRAVITY_MASK);
|
||||
if (height < 0) {
|
||||
lp.height = -2;
|
||||
}
|
||||
break;
|
||||
case 'middle':
|
||||
lp.gravity = GRAVITY_CENTER_VERTICAL | (gravity & HORIZONTAL_GRAVITY_MASK);
|
||||
if (height < 0) {
|
||||
lp.height = -2;
|
||||
}
|
||||
break;
|
||||
case 'bottom':
|
||||
lp.gravity = GRAVITY_BOTTOM | (gravity & HORIZONTAL_GRAVITY_MASK);
|
||||
if (height < 0) {
|
||||
lp.height = -2;
|
||||
}
|
||||
break;
|
||||
case 'stretch':
|
||||
lp.gravity = GRAVITY_FILL_VERTICAL | (gravity & HORIZONTAL_GRAVITY_MASK);
|
||||
if (height < 0) {
|
||||
lp.height = -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
nativeView.setLayoutParams(lp);
|
||||
}
|
||||
}
|
||||
|
||||
[testIDProperty.setNative](value: string) {
|
||||
this.setAccessibilityIdentifier(this.nativeViewProtected, value);
|
||||
}
|
||||
@@ -835,27 +946,17 @@ export class View extends ViewCommon {
|
||||
this.setAccessibilityIdentifier(this.nativeViewProtected, value);
|
||||
}
|
||||
|
||||
// @ts-expect-error
|
||||
[accessibilityRoleProperty.setNative](value: AccessibilityRole): void {
|
||||
this.accessibilityRole = value;
|
||||
updateA11yPropertiesCallback(this);
|
||||
|
||||
if (SDK_VERSION >= 28) {
|
||||
this.nativeViewProtected?.setAccessibilityHeading(value === AccessibilityRole.Header);
|
||||
}
|
||||
}
|
||||
|
||||
[accessibilityValueProperty.setNative](): void {
|
||||
[accessibilityValueProperty.setNative](value: string): void {
|
||||
this._androidContentDescriptionUpdated = true;
|
||||
updateContentDescription(this);
|
||||
}
|
||||
|
||||
[accessibilityLabelProperty.setNative](): void {
|
||||
[accessibilityLabelProperty.setNative](value: string): void {
|
||||
this._androidContentDescriptionUpdated = true;
|
||||
updateContentDescription(this);
|
||||
}
|
||||
|
||||
[accessibilityHintProperty.setNative](): void {
|
||||
[accessibilityHintProperty.setNative](value: string): void {
|
||||
this._androidContentDescriptionUpdated = true;
|
||||
updateContentDescription(this);
|
||||
}
|
||||
@@ -868,31 +969,7 @@ export class View extends ViewCommon {
|
||||
}
|
||||
}
|
||||
|
||||
// @ts-expect-error
|
||||
[accessibilityLiveRegionProperty.setNative](value: AccessibilityLiveRegion): void {
|
||||
switch (value) {
|
||||
case AccessibilityLiveRegion.Assertive: {
|
||||
this.nativeViewProtected.setAccessibilityLiveRegion(android.view.View.ACCESSIBILITY_LIVE_REGION_ASSERTIVE);
|
||||
break;
|
||||
}
|
||||
case AccessibilityLiveRegion.Polite: {
|
||||
this.nativeViewProtected.setAccessibilityLiveRegion(android.view.View.ACCESSIBILITY_LIVE_REGION_POLITE);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
this.nativeViewProtected.setAccessibilityLiveRegion(android.view.View.ACCESSIBILITY_LIVE_REGION_NONE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// @ts-expect-error
|
||||
[accessibilityStateProperty.setNative](value: AccessibilityState): void {
|
||||
this.accessibilityState = value;
|
||||
updateA11yPropertiesCallback(this);
|
||||
}
|
||||
|
||||
[accessibilityMediaSessionProperty.setNative](): void {
|
||||
[accessibilityMediaSessionProperty.setNative](value: string): void {
|
||||
updateA11yPropertiesCallback(this);
|
||||
}
|
||||
|
||||
@@ -976,88 +1053,6 @@ export class View extends ViewCommon {
|
||||
nativeView.setStateListAnimator(stateListAnimator);
|
||||
}
|
||||
|
||||
[horizontalAlignmentProperty.getDefault](): CoreTypes.HorizontalAlignmentType {
|
||||
return <CoreTypes.HorizontalAlignmentType>org.nativescript.widgets.ViewHelper.getHorizontalAlignment(this.nativeViewProtected);
|
||||
}
|
||||
// @ts-expect-error
|
||||
[horizontalAlignmentProperty.setNative](value: CoreTypes.HorizontalAlignmentType) {
|
||||
const nativeView = this.nativeViewProtected;
|
||||
const lp: any = nativeView.getLayoutParams() || new org.nativescript.widgets.CommonLayoutParams();
|
||||
const gravity = lp.gravity;
|
||||
const weight = lp.weight;
|
||||
// Set only if params gravity exists.
|
||||
if (gravity !== undefined) {
|
||||
switch (value) {
|
||||
case 'left':
|
||||
lp.gravity = GRAVITY_LEFT | (gravity & VERTICAL_GRAVITY_MASK);
|
||||
if (weight < 0) {
|
||||
lp.weight = -2;
|
||||
}
|
||||
break;
|
||||
case 'center':
|
||||
lp.gravity = GRAVITY_CENTER_HORIZONTAL | (gravity & VERTICAL_GRAVITY_MASK);
|
||||
if (weight < 0) {
|
||||
lp.weight = -2;
|
||||
}
|
||||
break;
|
||||
case 'right':
|
||||
lp.gravity = GRAVITY_RIGHT | (gravity & VERTICAL_GRAVITY_MASK);
|
||||
if (weight < 0) {
|
||||
lp.weight = -2;
|
||||
}
|
||||
break;
|
||||
case 'stretch':
|
||||
lp.gravity = GRAVITY_FILL_HORIZONTAL | (gravity & VERTICAL_GRAVITY_MASK);
|
||||
if (weight < 0) {
|
||||
lp.weight = -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
nativeView.setLayoutParams(lp);
|
||||
}
|
||||
}
|
||||
|
||||
[verticalAlignmentProperty.getDefault](): CoreTypes.VerticalAlignmentType {
|
||||
return <CoreTypes.VerticalAlignmentType>org.nativescript.widgets.ViewHelper.getVerticalAlignment(this.nativeViewProtected);
|
||||
}
|
||||
// @ts-expect-error
|
||||
[verticalAlignmentProperty.setNative](value: CoreTypes.VerticalAlignmentType) {
|
||||
const nativeView = this.nativeViewProtected;
|
||||
const lp: any = nativeView.getLayoutParams() || new org.nativescript.widgets.CommonLayoutParams();
|
||||
const gravity = lp.gravity;
|
||||
const height = lp.height;
|
||||
// Set only if params gravity exists.
|
||||
if (gravity !== undefined) {
|
||||
switch (value) {
|
||||
case 'top':
|
||||
lp.gravity = GRAVITY_TOP | (gravity & HORIZONTAL_GRAVITY_MASK);
|
||||
if (height < 0) {
|
||||
lp.height = -2;
|
||||
}
|
||||
break;
|
||||
case 'middle':
|
||||
lp.gravity = GRAVITY_CENTER_VERTICAL | (gravity & HORIZONTAL_GRAVITY_MASK);
|
||||
if (height < 0) {
|
||||
lp.height = -2;
|
||||
}
|
||||
break;
|
||||
case 'bottom':
|
||||
lp.gravity = GRAVITY_BOTTOM | (gravity & HORIZONTAL_GRAVITY_MASK);
|
||||
if (height < 0) {
|
||||
lp.height = -2;
|
||||
}
|
||||
break;
|
||||
case 'stretch':
|
||||
lp.gravity = GRAVITY_FILL_VERTICAL | (gravity & HORIZONTAL_GRAVITY_MASK);
|
||||
if (height < 0) {
|
||||
lp.height = -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
nativeView.setLayoutParams(lp);
|
||||
}
|
||||
}
|
||||
|
||||
[rotateProperty.setNative](value: number) {
|
||||
org.nativescript.widgets.ViewHelper.setRotate(this.nativeViewProtected, float(value));
|
||||
}
|
||||
|
||||
@@ -104,14 +104,13 @@ export class View extends ViewCommon {
|
||||
|
||||
@profile
|
||||
public layout(left: number, top: number, right: number, bottom: number, setFrame = true): void {
|
||||
const result = this._setCurrentLayoutBounds(left, top, right, bottom);
|
||||
let { sizeChanged } = result;
|
||||
const { boundsChanged, sizeChanged } = this._setCurrentLayoutBounds(left, top, right, bottom);
|
||||
|
||||
if (setFrame) {
|
||||
this.layoutNativeView(left, top, right, bottom);
|
||||
}
|
||||
|
||||
const needsLayout = result.boundsChanged || (this._privateFlags & PFLAG_LAYOUT_REQUIRED) === PFLAG_LAYOUT_REQUIRED;
|
||||
const needsLayout = boundsChanged || (this._privateFlags & PFLAG_LAYOUT_REQUIRED) === PFLAG_LAYOUT_REQUIRED;
|
||||
if (needsLayout) {
|
||||
let position: Position;
|
||||
|
||||
@@ -119,14 +118,6 @@ export class View extends ViewCommon {
|
||||
// on iOS 11+ it is possible to have a changed layout frame due to safe area insets
|
||||
// get the frame and adjust the position, so that onLayout works correctly
|
||||
position = IOSHelper.getPositionFromFrame(this.nativeViewProtected.frame);
|
||||
|
||||
if (!sizeChanged) {
|
||||
// If frame has actually changed, there is the need to update view background and border styles as they depend on native view bounds
|
||||
// To trigger the needed visual update, mark size as changed
|
||||
if (position.left !== left || position.top !== top || position.right !== right || position.bottom !== bottom) {
|
||||
sizeChanged = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
position = { left, top, right, bottom };
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Definitions.
|
||||
import { NavigationType } from './frame-common';
|
||||
import { NavigationType, TransitionState } from './frame-common';
|
||||
import { NavigationTransition, BackstackEntry } from '.';
|
||||
|
||||
// Types.
|
||||
@@ -152,7 +152,7 @@ export function _setAndroidFragmentTransitions(animated: boolean, navigationTran
|
||||
setupCurrentFragmentExplodeTransition(navigationTransition, currentEntry);
|
||||
}
|
||||
} else if (name.indexOf('flip') === 0) {
|
||||
const direction = name.substr('flip'.length) || 'right'; //Extract the direction from the string
|
||||
const direction = name.substring('flip'.length) || 'right'; //Extract the direction from the string
|
||||
const flipTransition = new FlipTransition(direction, navigationTransition.duration, navigationTransition.curve);
|
||||
|
||||
setupNewFragmentCustomTransition(navigationTransition, newEntry, flipTransition);
|
||||
@@ -282,23 +282,28 @@ export function _getAnimatedEntries(frameId: number): Set<BackstackEntry> {
|
||||
|
||||
export function _updateTransitions(entry: ExpandedEntry): void {
|
||||
const fragment = entry.fragment;
|
||||
|
||||
if (!fragment) {
|
||||
return;
|
||||
}
|
||||
|
||||
const enterTransitionListener = entry.enterTransitionListener;
|
||||
if (enterTransitionListener && fragment) {
|
||||
if (enterTransitionListener) {
|
||||
fragment.setEnterTransition(enterTransitionListener.transition);
|
||||
}
|
||||
|
||||
const exitTransitionListener = entry.exitTransitionListener;
|
||||
if (exitTransitionListener && fragment) {
|
||||
if (exitTransitionListener) {
|
||||
fragment.setExitTransition(exitTransitionListener.transition);
|
||||
}
|
||||
|
||||
const reenterTransitionListener = entry.reenterTransitionListener;
|
||||
if (reenterTransitionListener && fragment) {
|
||||
if (reenterTransitionListener) {
|
||||
fragment.setReenterTransition(reenterTransitionListener.transition);
|
||||
}
|
||||
|
||||
const returnTransitionListener = entry.returnTransitionListener;
|
||||
if (returnTransitionListener && fragment) {
|
||||
if (returnTransitionListener) {
|
||||
fragment.setReturnTransition(returnTransitionListener.transition);
|
||||
}
|
||||
}
|
||||
@@ -428,6 +433,16 @@ function addToWaitingQueue(entry: ExpandedEntry): void {
|
||||
entries.add(entry);
|
||||
}
|
||||
|
||||
function cloneExpandedTransitionListener(expandedTransitionListener: ExpandedTransitionListener) {
|
||||
if (!expandedTransitionListener) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const cloneTransition = expandedTransitionListener.transition.clone();
|
||||
|
||||
return addNativeTransitionListener(expandedTransitionListener.entry, cloneTransition);
|
||||
}
|
||||
|
||||
function clearExitAndReenterTransitions(entry: ExpandedEntry, removeListener: boolean): void {
|
||||
const fragment: androidx.fragment.app.Fragment = entry.fragment;
|
||||
const exitListener = entry.exitTransitionListener;
|
||||
@@ -469,15 +484,56 @@ function clearExitAndReenterTransitions(entry: ExpandedEntry, removeListener: bo
|
||||
}
|
||||
}
|
||||
|
||||
export function _getTransitionState(entry: ExpandedEntry): TransitionState {
|
||||
let transitionState: TransitionState;
|
||||
|
||||
if (entry.enterTransitionListener && entry.exitTransitionListener) {
|
||||
transitionState = {
|
||||
enterTransitionListener: cloneExpandedTransitionListener(entry.enterTransitionListener),
|
||||
exitTransitionListener: cloneExpandedTransitionListener(entry.exitTransitionListener),
|
||||
reenterTransitionListener: cloneExpandedTransitionListener(entry.reenterTransitionListener),
|
||||
returnTransitionListener: cloneExpandedTransitionListener(entry.returnTransitionListener),
|
||||
transitionName: entry.transitionName,
|
||||
entry,
|
||||
};
|
||||
} else {
|
||||
transitionState = null;
|
||||
}
|
||||
|
||||
return transitionState;
|
||||
}
|
||||
|
||||
export function _restoreTransitionState(snapshot: TransitionState): void {
|
||||
const entry = snapshot.entry as ExpandedEntry;
|
||||
|
||||
if (snapshot.enterTransitionListener) {
|
||||
entry.enterTransitionListener = snapshot.enterTransitionListener;
|
||||
}
|
||||
|
||||
if (snapshot.exitTransitionListener) {
|
||||
entry.exitTransitionListener = snapshot.exitTransitionListener;
|
||||
}
|
||||
|
||||
if (snapshot.reenterTransitionListener) {
|
||||
entry.reenterTransitionListener = snapshot.reenterTransitionListener;
|
||||
}
|
||||
|
||||
if (snapshot.returnTransitionListener) {
|
||||
entry.returnTransitionListener = snapshot.returnTransitionListener;
|
||||
}
|
||||
|
||||
entry.transitionName = snapshot.transitionName;
|
||||
}
|
||||
|
||||
export function _clearFragment(entry: ExpandedEntry): void {
|
||||
clearEntry(entry, false);
|
||||
clearTransitions(entry, false);
|
||||
}
|
||||
|
||||
export function _clearEntry(entry: ExpandedEntry): void {
|
||||
clearEntry(entry, true);
|
||||
clearTransitions(entry, true);
|
||||
}
|
||||
|
||||
function clearEntry(entry: ExpandedEntry, removeListener: boolean): void {
|
||||
function clearTransitions(entry: ExpandedEntry, removeListener: boolean): void {
|
||||
clearExitAndReenterTransitions(entry, removeListener);
|
||||
|
||||
const fragment: androidx.fragment.app.Fragment = entry.fragment;
|
||||
@@ -569,7 +625,7 @@ function setReturnTransition(navigationTransition: NavigationTransition, entry:
|
||||
|
||||
function setupNewFragmentSlideTransition(navTransition: NavigationTransition, entry: ExpandedEntry, name: string): void {
|
||||
setupCurrentFragmentSlideTransition(navTransition, entry, name);
|
||||
const direction = name.substr('slide'.length) || 'left'; //Extract the direction from the string
|
||||
const direction = name.substring('slide'.length) || 'left'; //Extract the direction from the string
|
||||
switch (direction) {
|
||||
case 'left':
|
||||
setEnterTransition(navTransition, entry, new androidx.transition.Slide(android.view.Gravity.RIGHT));
|
||||
@@ -594,7 +650,7 @@ function setupNewFragmentSlideTransition(navTransition: NavigationTransition, en
|
||||
}
|
||||
|
||||
function setupCurrentFragmentSlideTransition(navTransition: NavigationTransition, entry: ExpandedEntry, name: string): void {
|
||||
const direction = name.substr('slide'.length) || 'left'; //Extract the direction from the string
|
||||
const direction = name.substring('slide'.length) || 'left'; //Extract the direction from the string
|
||||
switch (direction) {
|
||||
case 'left':
|
||||
setExitTransition(navTransition, entry, new androidx.transition.Slide(android.view.Gravity.LEFT));
|
||||
|
||||
10
packages/core/ui/frame/fragment.transitions.d.ts
vendored
10
packages/core/ui/frame/fragment.transitions.d.ts
vendored
@@ -1,4 +1,4 @@
|
||||
import { NavigationTransition, BackstackEntry } from '.';
|
||||
import { NavigationTransition, BackstackEntry, TransitionState } from '.';
|
||||
|
||||
/**
|
||||
* @private
|
||||
@@ -20,6 +20,14 @@ export function _updateTransitions(entry: BackstackEntry): void;
|
||||
* Reverse transitions from entry to fragment if any.
|
||||
*/
|
||||
export function _reverseTransitions(previousEntry: BackstackEntry, currentEntry: BackstackEntry): boolean;
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
export function _getTransitionState(entry: BackstackEntry): TransitionState;
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
export function _restoreTransitionState(snapshot: TransitionState): void;
|
||||
/**
|
||||
* @private
|
||||
* Called when entry is removed from backstack (either back navigation or
|
||||
|
||||
@@ -76,13 +76,13 @@ export class FrameBase extends CustomLayoutView {
|
||||
return true;
|
||||
} else if (top) {
|
||||
let parentFrameCanGoBack = false;
|
||||
let parentFrame = <FrameBase>getAncestor(top, 'Frame');
|
||||
let parentFrame = getAncestor(top, 'Frame');
|
||||
|
||||
while (parentFrame && !parentFrameCanGoBack) {
|
||||
if (parentFrame && parentFrame.canGoBack()) {
|
||||
parentFrameCanGoBack = true;
|
||||
} else {
|
||||
parentFrame = <FrameBase>getAncestor(parentFrame, 'Frame');
|
||||
parentFrame = getAncestor(parentFrame, 'Frame');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,7 +122,6 @@ export class FrameBase extends CustomLayoutView {
|
||||
@profile
|
||||
public onLoaded() {
|
||||
super.onLoaded();
|
||||
|
||||
this._processNextNavigationEntry();
|
||||
}
|
||||
|
||||
@@ -323,9 +322,10 @@ export class FrameBase extends CustomLayoutView {
|
||||
}
|
||||
|
||||
private isNestedWithin(parentFrameCandidate: FrameBase): boolean {
|
||||
let frameAncestor: FrameBase = this;
|
||||
let frameAncestor = this as FrameBase;
|
||||
|
||||
while (frameAncestor) {
|
||||
frameAncestor = <FrameBase>getAncestor(frameAncestor, FrameBase);
|
||||
frameAncestor = getAncestor(frameAncestor, FrameBase);
|
||||
if (frameAncestor === parentFrameCandidate) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import { Observable } from '../../data/observable';
|
||||
import { Trace } from '../../trace';
|
||||
import { View } from '../core/view';
|
||||
import { _stack, FrameBase, NavigationType } from './frame-common';
|
||||
import { _clearEntry, _clearFragment, _getAnimatedEntries, _reverseTransitions, _setAndroidFragmentTransitions, _updateTransitions, addNativeTransitionListener } from './fragment.transitions';
|
||||
import { _clearEntry, _clearFragment, _getAnimatedEntries, _getTransitionState, _restoreTransitionState, _reverseTransitions, _setAndroidFragmentTransitions, _updateTransitions, addNativeTransitionListener } from './fragment.transitions';
|
||||
import { profile } from '../../profiling';
|
||||
import { android as androidUtils } from '../../utils/native-helper';
|
||||
import type { ExpandedEntry } from './fragment.transitions.android';
|
||||
@@ -23,6 +23,7 @@ export { setFragmentClass } from './fragment';
|
||||
const INTENT_EXTRA = 'com.tns.activity';
|
||||
|
||||
const ownerSymbol = Symbol('_owner');
|
||||
const isPendingDetachSymbol = Symbol('_isPendingDetach');
|
||||
|
||||
let navDepth = -1;
|
||||
let fragmentId = -1;
|
||||
@@ -51,6 +52,12 @@ function getAttachListener(): android.view.View.OnAttachStateChangeListener {
|
||||
if (owner) {
|
||||
owner._onDetachedFromWindow();
|
||||
}
|
||||
|
||||
if (view[isPendingDetachSymbol]) {
|
||||
delete view[isPendingDetachSymbol];
|
||||
view.removeOnAttachStateChangeListener(this);
|
||||
view[ownerSymbol] = null;
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
@@ -66,7 +73,10 @@ export class Frame extends FrameBase {
|
||||
private _containerViewId = -1;
|
||||
private _tearDownPending = false;
|
||||
private _attachedToWindow = false;
|
||||
private _wasReset = false;
|
||||
/**
|
||||
* This property indicates that the view is to be reused as a root view or has been previously disposed.
|
||||
*/
|
||||
private _isReset = false;
|
||||
private _cachedTransitionState: TransitionState;
|
||||
private _frameCreateTimeout: NodeJS.Timeout;
|
||||
|
||||
@@ -136,8 +146,9 @@ export class Frame extends FrameBase {
|
||||
}
|
||||
|
||||
this._attachedToWindow = true;
|
||||
this._wasReset = false;
|
||||
this._isReset = false;
|
||||
this._processNextNavigationEntry();
|
||||
this._ensureEntryFragment();
|
||||
}
|
||||
|
||||
_onDetachedFromWindow(): void {
|
||||
@@ -155,12 +166,12 @@ export class Frame extends FrameBase {
|
||||
return;
|
||||
}
|
||||
|
||||
// in case the activity is "reset" using resetRootView we must wait for
|
||||
// in case the activity is "reset" using resetRootView or disposed we must wait for
|
||||
// the attachedToWindow event to make the first navigation or it will crash
|
||||
// https://github.com/NativeScript/NativeScript/commit/9dd3e1a8076e5022e411f2f2eeba34aabc68d112
|
||||
// though we should not do it on app "start"
|
||||
// or it will create a "flash" to activity background color
|
||||
if (this._wasReset && !this._attachedToWindow) {
|
||||
if (this._isReset && !this._attachedToWindow) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -187,7 +198,7 @@ export class Frame extends FrameBase {
|
||||
// simulated navigation (NoTransition, zero duration animator) and thus the fragment immediately disappears;
|
||||
// the user only sees the animation of the entering fragment as per its specific enter animation settings.
|
||||
// NOTE: we are restoring the animation settings in Frame.setCurrent(...) as navigation completes asynchronously
|
||||
const cachedTransitionState = getTransitionState(this._currentEntry);
|
||||
const cachedTransitionState = _getTransitionState(this._currentEntry);
|
||||
|
||||
if (cachedTransitionState) {
|
||||
this._cachedTransitionState = cachedTransitionState;
|
||||
@@ -221,7 +232,7 @@ export class Frame extends FrameBase {
|
||||
public _onRootViewReset(): void {
|
||||
super._onRootViewReset();
|
||||
// used to handle the "first" navigate differently on first run and on reset
|
||||
this._wasReset = true;
|
||||
this._isReset = true;
|
||||
// call this AFTER the super call to ensure descendants apply their rootview-reset logic first
|
||||
// i.e. in a scenario with nested frames / frame with tabview let the descendandt cleanup the inner
|
||||
// fragments first, and then cleanup the parent fragments
|
||||
@@ -234,6 +245,33 @@ export class Frame extends FrameBase {
|
||||
this.backgroundColor = this._originalBackground;
|
||||
this._originalBackground = null;
|
||||
}
|
||||
|
||||
this._ensureEntryFragment();
|
||||
super.onLoaded();
|
||||
}
|
||||
|
||||
onUnloaded() {
|
||||
super.onUnloaded();
|
||||
|
||||
if (typeof this._frameCreateTimeout === 'number') {
|
||||
clearTimeout(this._frameCreateTimeout);
|
||||
this._frameCreateTimeout = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Check if this fragment precaution is still needed
|
||||
*/
|
||||
private _ensureEntryFragment(): void {
|
||||
// in case the activity is "reset" using resetRootView or disposed we must wait for
|
||||
// the attachedToWindow event to make the first navigation or it will crash
|
||||
// https://github.com/NativeScript/NativeScript/commit/9dd3e1a8076e5022e411f2f2eeba34aabc68d112
|
||||
// though we should not do it on app "start"
|
||||
// or it will create a "flash" to activity background color
|
||||
if (this._isReset && !this._attachedToWindow) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._frameCreateTimeout = setTimeout(() => {
|
||||
// there's a bug with nested frames where sometimes the nested fragment is not recreated at all
|
||||
// so we manually check on loaded event if the fragment is not recreated and recreate it
|
||||
@@ -248,17 +286,9 @@ export class Frame extends FrameBase {
|
||||
transaction.commitAllowingStateLoss();
|
||||
}
|
||||
}
|
||||
}, 0);
|
||||
|
||||
super.onLoaded();
|
||||
}
|
||||
|
||||
onUnloaded() {
|
||||
super.onUnloaded();
|
||||
if (typeof this._frameCreateTimeout === 'number') {
|
||||
clearTimeout(this._frameCreateTimeout);
|
||||
this._frameCreateTimeout = null;
|
||||
}
|
||||
}, 0);
|
||||
}
|
||||
|
||||
private disposeCurrentFragment(): void {
|
||||
@@ -345,7 +375,7 @@ export class Frame extends FrameBase {
|
||||
|
||||
// restore cached animation settings if we just completed simulated first navigation (no animation)
|
||||
if (this._cachedTransitionState) {
|
||||
restoreTransitionState(this._currentEntry, this._cachedTransitionState);
|
||||
_restoreTransitionState(this._cachedTransitionState);
|
||||
this._cachedTransitionState = null;
|
||||
}
|
||||
|
||||
@@ -384,7 +414,7 @@ export class Frame extends FrameBase {
|
||||
// HACK: This @profile decorator creates a circular dependency
|
||||
// HACK: because the function parameter type is evaluated with 'typeof'
|
||||
@profile
|
||||
public _navigateCore(newEntry: any) {
|
||||
public _navigateCore(newEntry: BackstackEntry) {
|
||||
// should be (newEntry: BackstackEntry)
|
||||
super._navigateCore(newEntry);
|
||||
|
||||
@@ -480,19 +510,19 @@ export class Frame extends FrameBase {
|
||||
|
||||
if (removed.fragment) {
|
||||
_clearEntry(removed);
|
||||
removed.fragment = null;
|
||||
}
|
||||
|
||||
removed.fragment = null;
|
||||
removed.viewSavedState = null;
|
||||
}
|
||||
|
||||
protected _disposeBackstackEntry(entry: BackstackEntry): void {
|
||||
if (entry.fragment) {
|
||||
_clearFragment(entry);
|
||||
entry.fragment = null;
|
||||
}
|
||||
|
||||
entry.recreated = false;
|
||||
entry.fragment = null;
|
||||
|
||||
super._disposeBackstackEntry(entry);
|
||||
}
|
||||
@@ -511,9 +541,12 @@ export class Frame extends FrameBase {
|
||||
public initNativeView(): void {
|
||||
super.initNativeView();
|
||||
const listener = getAttachListener();
|
||||
this.nativeViewProtected.addOnAttachStateChangeListener(listener);
|
||||
this.nativeViewProtected[ownerSymbol] = this;
|
||||
this._android.rootViewGroup = this.nativeViewProtected;
|
||||
const nativeView = this.nativeViewProtected as android.view.ViewGroup;
|
||||
|
||||
nativeView.addOnAttachStateChangeListener(listener);
|
||||
nativeView[ownerSymbol] = this;
|
||||
|
||||
this._android.rootViewGroup = nativeView;
|
||||
if (this._containerViewId < 0) {
|
||||
this._containerViewId = android.view.View.generateViewId();
|
||||
}
|
||||
@@ -521,12 +554,23 @@ export class Frame extends FrameBase {
|
||||
}
|
||||
|
||||
public disposeNativeView() {
|
||||
const nativeView = this.nativeViewProtected as android.view.ViewGroup;
|
||||
const listener = getAttachListener();
|
||||
this.nativeViewProtected.removeOnAttachStateChangeListener(listener);
|
||||
this.nativeViewProtected[ownerSymbol] = null;
|
||||
|
||||
// There are cases like root view when detach listener is not called upon removing view from view-tree
|
||||
// so mark those views as pending and remove listener once the view is detached
|
||||
if (nativeView.isAttachedToWindow()) {
|
||||
nativeView[isPendingDetachSymbol] = true;
|
||||
} else {
|
||||
nativeView.removeOnAttachStateChangeListener(listener);
|
||||
nativeView[ownerSymbol] = null;
|
||||
}
|
||||
|
||||
this._tearDownPending = !!this._executingContext;
|
||||
|
||||
const current = this._currentEntry;
|
||||
const executingEntry = this._executingContext ? this._executingContext.entry : null;
|
||||
|
||||
this.backStack.forEach((entry) => {
|
||||
// Don't destroy current and executing entries or UI will look blank.
|
||||
// We will do it in setCurrent.
|
||||
@@ -539,6 +583,12 @@ export class Frame extends FrameBase {
|
||||
this._disposeBackstackEntry(current);
|
||||
}
|
||||
|
||||
// Dispose cached transition and store it again if view ever gets re-used
|
||||
this._cachedTransitionState = null;
|
||||
|
||||
// Mark as reset in order to properly re-initialize fragments if view ever gets re-used
|
||||
this._isReset = true;
|
||||
|
||||
this._android.rootViewGroup = null;
|
||||
this._removeFromFrameStack();
|
||||
super.disposeNativeView();
|
||||
@@ -596,55 +646,6 @@ export function reloadPage(context?: ModuleContext): void {
|
||||
// attach on global, so it can be overwritten in NativeScript Angular
|
||||
global.__onLiveSyncCore = Frame.reloadPage;
|
||||
|
||||
function cloneExpandedTransitionListener(expandedTransitionListener: any) {
|
||||
if (!expandedTransitionListener) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const cloneTransition = expandedTransitionListener.transition.clone();
|
||||
|
||||
return addNativeTransitionListener(expandedTransitionListener.entry, cloneTransition);
|
||||
}
|
||||
|
||||
function getTransitionState(entry: BackstackEntry): TransitionState {
|
||||
const expandedEntry = <any>entry;
|
||||
const transitionState = <TransitionState>{};
|
||||
|
||||
if (expandedEntry.enterTransitionListener && expandedEntry.exitTransitionListener) {
|
||||
transitionState.enterTransitionListener = cloneExpandedTransitionListener(expandedEntry.enterTransitionListener);
|
||||
transitionState.exitTransitionListener = cloneExpandedTransitionListener(expandedEntry.exitTransitionListener);
|
||||
transitionState.reenterTransitionListener = cloneExpandedTransitionListener(expandedEntry.reenterTransitionListener);
|
||||
transitionState.returnTransitionListener = cloneExpandedTransitionListener(expandedEntry.returnTransitionListener);
|
||||
transitionState.transitionName = expandedEntry.transitionName;
|
||||
transitionState.entry = entry;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
return transitionState;
|
||||
}
|
||||
|
||||
function restoreTransitionState(entry: BackstackEntry, snapshot: TransitionState): void {
|
||||
const expandedEntry = <any>entry;
|
||||
if (snapshot.enterTransitionListener) {
|
||||
expandedEntry.enterTransitionListener = snapshot.enterTransitionListener;
|
||||
}
|
||||
|
||||
if (snapshot.exitTransitionListener) {
|
||||
expandedEntry.exitTransitionListener = snapshot.exitTransitionListener;
|
||||
}
|
||||
|
||||
if (snapshot.reenterTransitionListener) {
|
||||
expandedEntry.reenterTransitionListener = snapshot.reenterTransitionListener;
|
||||
}
|
||||
|
||||
if (snapshot.returnTransitionListener) {
|
||||
expandedEntry.returnTransitionListener = snapshot.returnTransitionListener;
|
||||
}
|
||||
|
||||
expandedEntry.transitionName = snapshot.transitionName;
|
||||
}
|
||||
|
||||
let framesCounter = 0;
|
||||
|
||||
class AndroidFrame extends Observable implements AndroidFrameDefinition {
|
||||
|
||||
@@ -97,7 +97,7 @@ export class Frame extends FrameBase {
|
||||
// !!! THIS PROFILE DECORATOR CREATES A CIRCULAR DEPENDENCY
|
||||
// !!! BECAUSE THE PARAMETER TYPE IS EVALUATED WITH TYPEOF
|
||||
@profile
|
||||
public _navigateCore(backstackEntry: any) {
|
||||
public _navigateCore(backstackEntry: BackstackEntry) {
|
||||
super._navigateCore(backstackEntry);
|
||||
|
||||
const viewController: UIViewController = backstackEntry.resolvedPage.ios;
|
||||
@@ -507,7 +507,7 @@ class UINavigationControllerImpl extends UINavigationController {
|
||||
}
|
||||
}
|
||||
|
||||
private animateWithDuration(navigationTransition: NavigationTransition, nativeTransition: UIViewAnimationTransition, transitionType: string, baseCallback: Function): void {
|
||||
private animateWithDuration(navigationTransition: NavigationTransition, nativeTransition: UIViewAnimationTransition, transitionType: string, baseCallback: () => void): void {
|
||||
const duration = navigationTransition.duration ? navigationTransition.duration / 1000 : CORE_ANIMATION_DEFAULTS.duration;
|
||||
const curve = _getNativeCurve(navigationTransition);
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { ImageBase, stretchProperty, imageSourceProperty, tintColorProperty, srcProperty, iosSymbolEffectProperty, ImageSymbolEffect, ImageSymbolEffects, iosSymbolScaleProperty } from './image-common';
|
||||
import { ImageSource, iosSymbolScaleType } from '../../image-source';
|
||||
import { ImageSource } from '../../image-source';
|
||||
import { ImageAsset } from '../../image-asset';
|
||||
import { Color } from '../../color';
|
||||
import { Trace } from '../../trace';
|
||||
@@ -219,8 +219,7 @@ export class Image extends ImageBase {
|
||||
}
|
||||
}
|
||||
|
||||
// @ts-expect-error
|
||||
[iosSymbolScaleProperty.setNative](value: iosSymbolScaleType) {
|
||||
[iosSymbolScaleProperty.setNative](value: string) {
|
||||
// reset src to configure scale
|
||||
this._setSrc(this.src);
|
||||
}
|
||||
|
||||
@@ -68,6 +68,7 @@ class FlexLine {
|
||||
_dividerLengthInMainSize = 0;
|
||||
_crossSize = 0;
|
||||
_itemCount = 0;
|
||||
_goneItemCount = 0;
|
||||
_totalFlexGrow = 0;
|
||||
_totalFlexShrink = 0;
|
||||
_maxBaseline = 0;
|
||||
@@ -96,6 +97,9 @@ class FlexLine {
|
||||
get itemCount(): number {
|
||||
return this._itemCount;
|
||||
}
|
||||
get layoutVisibleItemCount(): number {
|
||||
return this._itemCount - this._goneItemCount;
|
||||
}
|
||||
get totalFlexGrow(): number {
|
||||
return this._totalFlexGrow;
|
||||
}
|
||||
@@ -250,6 +254,7 @@ export class FlexboxLayout extends FlexboxLayoutBase {
|
||||
continue;
|
||||
} else if (child.isCollapsed) {
|
||||
flexLine._itemCount++;
|
||||
flexLine._goneItemCount++;
|
||||
this._addFlexLineIfLastFlexItem(i, childCount, flexLine);
|
||||
continue;
|
||||
}
|
||||
@@ -277,7 +282,7 @@ export class FlexboxLayout extends FlexboxLayoutBase {
|
||||
largestHeightInRow = Math.max(largestHeightInRow, child.getMeasuredHeight() + lp.effectiveMarginTop + lp.effectiveMarginBottom);
|
||||
|
||||
if (this._isWrapRequired(child, widthMode, widthSize, flexLine._mainSize, child.getMeasuredWidth() + lp.effectiveMarginLeft + lp.effectiveMarginRight, i, indexInFlexLine)) {
|
||||
if (flexLine.itemCount > 0) {
|
||||
if (flexLine.layoutVisibleItemCount > 0) {
|
||||
this._addFlexLine(flexLine);
|
||||
}
|
||||
|
||||
@@ -319,11 +324,11 @@ export class FlexboxLayout extends FlexboxLayoutBase {
|
||||
if (this.flexWrap !== FlexWrap.WRAP_REVERSE) {
|
||||
let marginTop = flexLine._maxBaseline - FlexboxLayout.getBaseline(child);
|
||||
marginTop = Math.max(marginTop, lp.effectiveMarginTop);
|
||||
largestHeightInLine = Math.max(largestHeightInLine, child.getActualSize().height + marginTop + lp.effectiveMarginBottom);
|
||||
largestHeightInLine = Math.max(largestHeightInLine, child.getMeasuredHeight() + marginTop + lp.effectiveMarginBottom);
|
||||
} else {
|
||||
let marginBottom = flexLine._maxBaseline - child.getMeasuredHeight() + FlexboxLayout.getBaseline(child);
|
||||
marginBottom = Math.max(marginBottom, lp.effectiveMarginBottom);
|
||||
largestHeightInLine = Math.max(largestHeightInLine, child.getActualSize().height + lp.effectiveMarginTop + marginBottom);
|
||||
largestHeightInLine = Math.max(largestHeightInLine, child.getMeasuredHeight() + lp.effectiveMarginTop + marginBottom);
|
||||
}
|
||||
}
|
||||
flexLine._crossSize = largestHeightInLine;
|
||||
@@ -360,6 +365,7 @@ export class FlexboxLayout extends FlexboxLayoutBase {
|
||||
continue;
|
||||
} else if (child.isCollapsed) {
|
||||
flexLine._itemCount++;
|
||||
flexLine._goneItemCount++;
|
||||
this._addFlexLineIfLastFlexItem(i, childCount, flexLine);
|
||||
continue;
|
||||
}
|
||||
@@ -386,7 +392,7 @@ export class FlexboxLayout extends FlexboxLayoutBase {
|
||||
largestWidthInColumn = Math.max(largestWidthInColumn, child.getMeasuredWidth() + lp.effectiveMarginLeft + lp.effectiveMarginRight);
|
||||
|
||||
if (this._isWrapRequired(child, heightMode, heightSize, flexLine.mainSize, child.getMeasuredHeight() + lp.effectiveMarginTop + lp.effectiveMarginBottom, i, indexInFlexLine)) {
|
||||
if (flexLine._itemCount > 0) {
|
||||
if (flexLine.layoutVisibleItemCount > 0) {
|
||||
this._addFlexLine(flexLine);
|
||||
}
|
||||
|
||||
@@ -448,7 +454,7 @@ export class FlexboxLayout extends FlexboxLayoutBase {
|
||||
}
|
||||
|
||||
private _addFlexLineIfLastFlexItem(childIndex: number, childCount: number, flexLine: FlexLine) {
|
||||
if (childIndex === childCount - 1 && flexLine.itemCount !== 0) {
|
||||
if (childIndex === childCount - 1 && flexLine.layoutVisibleItemCount !== 0) {
|
||||
this._addFlexLine(flexLine);
|
||||
}
|
||||
}
|
||||
@@ -1013,16 +1019,20 @@ export class FlexboxLayout extends FlexboxLayoutBase {
|
||||
childLeft = paddingLeft + (width - insets.left - insets.right - flexLine._mainSize) / 2.0;
|
||||
childRight = width - paddingRight - (width - insets.left - insets.right - flexLine._mainSize) / 2.0;
|
||||
break;
|
||||
case JustifyContent.SPACE_AROUND:
|
||||
if (flexLine._itemCount !== 0) {
|
||||
spaceBetweenItem = (width - insets.left - insets.right - flexLine.mainSize) / flexLine._itemCount;
|
||||
case JustifyContent.SPACE_AROUND: {
|
||||
const visibleCount = flexLine.layoutVisibleItemCount;
|
||||
if (visibleCount !== 0) {
|
||||
spaceBetweenItem = (width - insets.left - insets.right - flexLine.mainSize) / visibleCount;
|
||||
}
|
||||
childLeft = paddingLeft + spaceBetweenItem / 2.0;
|
||||
childRight = width - paddingRight - spaceBetweenItem / 2.0;
|
||||
break;
|
||||
}
|
||||
case JustifyContent.SPACE_BETWEEN: {
|
||||
const visibleCount = flexLine.layoutVisibleItemCount;
|
||||
const denominator = visibleCount !== 1 ? visibleCount - 1 : 1.0;
|
||||
|
||||
childLeft = paddingLeft;
|
||||
const denominator = flexLine.itemCount !== 1 ? flexLine.itemCount - 1 : 1.0;
|
||||
spaceBetweenItem = (width - insets.left - insets.right - flexLine.mainSize) / denominator;
|
||||
childRight = width - paddingRight;
|
||||
break;
|
||||
@@ -1157,16 +1167,20 @@ export class FlexboxLayout extends FlexboxLayoutBase {
|
||||
childTop = paddingTop + (height - insets.top - insets.bottom - flexLine._mainSize) / 2.0;
|
||||
childBottom = height - paddingBottom - (height - insets.top - insets.bottom - flexLine._mainSize) / 2.0;
|
||||
break;
|
||||
case JustifyContent.SPACE_AROUND:
|
||||
if (flexLine._itemCount !== 0) {
|
||||
spaceBetweenItem = (height - insets.top - insets.bottom - flexLine._mainSize) / flexLine.itemCount;
|
||||
case JustifyContent.SPACE_AROUND: {
|
||||
const visibleCount = flexLine.layoutVisibleItemCount;
|
||||
if (visibleCount !== 0) {
|
||||
spaceBetweenItem = (height - insets.top - insets.bottom - flexLine._mainSize) / visibleCount;
|
||||
}
|
||||
childTop = paddingTop + spaceBetweenItem / 2.0;
|
||||
childBottom = height - paddingBottom - spaceBetweenItem / 2.0;
|
||||
break;
|
||||
}
|
||||
case JustifyContent.SPACE_BETWEEN: {
|
||||
const visibleCount = flexLine.layoutVisibleItemCount;
|
||||
const denominator = visibleCount !== 1 ? visibleCount - 1 : 1.0;
|
||||
|
||||
childTop = paddingTop;
|
||||
const denominator = flexLine.itemCount !== 1 ? flexLine.itemCount - 1 : 1.0;
|
||||
spaceBetweenItem = (height - insets.top - insets.bottom - flexLine.mainSize) / denominator;
|
||||
childBottom = height - paddingBottom;
|
||||
break;
|
||||
|
||||
@@ -4,6 +4,7 @@ import { isUserInteractionEnabledProperty, isEnabledProperty } from '../core/vie
|
||||
import { ad } from '../../utils';
|
||||
import { Color } from '../../color';
|
||||
import { colorProperty, backgroundColorProperty, backgroundInternalProperty, fontInternalProperty, fontSizeProperty } from '../styling/style-properties';
|
||||
import { Background } from '../styling/background';
|
||||
|
||||
export * from './search-bar-common';
|
||||
|
||||
@@ -227,14 +228,13 @@ export class SearchBar extends SearchBarBase {
|
||||
[backgroundInternalProperty.getDefault](): any {
|
||||
return null;
|
||||
}
|
||||
[backgroundInternalProperty.setNative](value: any) {
|
||||
[backgroundInternalProperty.setNative](value: android.graphics.drawable.Drawable | Background) {
|
||||
//
|
||||
}
|
||||
|
||||
[textProperty.getDefault](): string {
|
||||
return '';
|
||||
}
|
||||
// @ts-expect-error
|
||||
[textProperty.setNative](value: string) {
|
||||
const text = value === null || value === undefined ? '' : value.toString();
|
||||
this.nativeViewProtected.setQuery(text, false);
|
||||
@@ -242,7 +242,6 @@ export class SearchBar extends SearchBarBase {
|
||||
[hintProperty.getDefault](): string {
|
||||
return null;
|
||||
}
|
||||
// @ts-expect-error
|
||||
[hintProperty.setNative](value: string) {
|
||||
if (value === null || value === undefined) {
|
||||
this.nativeViewProtected.setQueryHint(null);
|
||||
|
||||
@@ -158,14 +158,13 @@ export class SearchBar extends SearchBarBase {
|
||||
[backgroundInternalProperty.getDefault](): any {
|
||||
return null;
|
||||
}
|
||||
[backgroundInternalProperty.setNative](value: any) {
|
||||
[backgroundInternalProperty.setNative](value: UIColor) {
|
||||
//
|
||||
}
|
||||
|
||||
[textProperty.getDefault](): string {
|
||||
return '';
|
||||
}
|
||||
// @ts-expect-error
|
||||
[textProperty.setNative](value: string) {
|
||||
const text = value === null || value === undefined ? '' : value.toString();
|
||||
this.ios.text = text;
|
||||
@@ -174,7 +173,6 @@ export class SearchBar extends SearchBarBase {
|
||||
[hintProperty.getDefault](): string {
|
||||
return '';
|
||||
}
|
||||
// @ts-expect-error
|
||||
[hintProperty.setNative](value: string) {
|
||||
this._updateAttributedPlaceholder();
|
||||
}
|
||||
|
||||
@@ -386,13 +386,6 @@ export class TextBase extends TextBaseCommon {
|
||||
}
|
||||
}
|
||||
|
||||
[lineHeightProperty.getDefault](): number {
|
||||
return this.nativeTextViewProtected.getLineSpacingExtra() / layout.getDisplayDensity();
|
||||
}
|
||||
[lineHeightProperty.setNative](value: number) {
|
||||
this.nativeTextViewProtected.setLineSpacing(value * layout.getDisplayDensity(), 1);
|
||||
}
|
||||
|
||||
[fontInternalProperty.getDefault](): android.graphics.Typeface {
|
||||
return this.nativeTextViewProtected.getTypeface();
|
||||
}
|
||||
@@ -446,17 +439,9 @@ export class TextBase extends TextBaseCommon {
|
||||
);
|
||||
}
|
||||
|
||||
[letterSpacingProperty.getDefault](): number {
|
||||
return org.nativescript.widgets.ViewHelper.getLetterspacing(this.nativeTextViewProtected);
|
||||
}
|
||||
[letterSpacingProperty.setNative](value: number) {
|
||||
org.nativescript.widgets.ViewHelper.setLetterspacing(this.nativeTextViewProtected, value);
|
||||
}
|
||||
|
||||
[paddingTopProperty.getDefault](): CoreTypes.LengthType {
|
||||
return { value: this._defaultPaddingTop, unit: 'px' };
|
||||
}
|
||||
// @ts-expect-error
|
||||
[paddingTopProperty.setNative](value: CoreTypes.LengthType) {
|
||||
org.nativescript.widgets.ViewHelper.setPaddingTop(this.nativeTextViewProtected, Length.toDevicePixels(value, 0) + Length.toDevicePixels(this.style.borderTopWidth, 0));
|
||||
}
|
||||
@@ -464,7 +449,6 @@ export class TextBase extends TextBaseCommon {
|
||||
[paddingRightProperty.getDefault](): CoreTypes.LengthType {
|
||||
return { value: this._defaultPaddingRight, unit: 'px' };
|
||||
}
|
||||
// @ts-expect-error
|
||||
[paddingRightProperty.setNative](value: CoreTypes.LengthType) {
|
||||
org.nativescript.widgets.ViewHelper.setPaddingRight(this.nativeTextViewProtected, Length.toDevicePixels(value, 0) + Length.toDevicePixels(this.style.borderRightWidth, 0));
|
||||
}
|
||||
@@ -472,7 +456,6 @@ export class TextBase extends TextBaseCommon {
|
||||
[paddingBottomProperty.getDefault](): CoreTypes.LengthType {
|
||||
return { value: this._defaultPaddingBottom, unit: 'px' };
|
||||
}
|
||||
// @ts-expect-error
|
||||
[paddingBottomProperty.setNative](value: CoreTypes.LengthType) {
|
||||
org.nativescript.widgets.ViewHelper.setPaddingBottom(this.nativeTextViewProtected, Length.toDevicePixels(value, 0) + Length.toDevicePixels(this.style.borderBottomWidth, 0));
|
||||
}
|
||||
@@ -480,11 +463,24 @@ export class TextBase extends TextBaseCommon {
|
||||
[paddingLeftProperty.getDefault](): CoreTypes.LengthType {
|
||||
return { value: this._defaultPaddingLeft, unit: 'px' };
|
||||
}
|
||||
// @ts-expect-error
|
||||
[paddingLeftProperty.setNative](value: CoreTypes.LengthType) {
|
||||
org.nativescript.widgets.ViewHelper.setPaddingLeft(this.nativeTextViewProtected, Length.toDevicePixels(value, 0) + Length.toDevicePixels(this.style.borderLeftWidth, 0));
|
||||
}
|
||||
|
||||
[lineHeightProperty.getDefault](): number {
|
||||
return this.nativeTextViewProtected.getLineSpacingExtra() / layout.getDisplayDensity();
|
||||
}
|
||||
[lineHeightProperty.setNative](value: number) {
|
||||
this.nativeTextViewProtected.setLineSpacing(value * layout.getDisplayDensity(), 1);
|
||||
}
|
||||
|
||||
[letterSpacingProperty.getDefault](): number {
|
||||
return org.nativescript.widgets.ViewHelper.getLetterspacing(this.nativeTextViewProtected);
|
||||
}
|
||||
[letterSpacingProperty.setNative](value: number) {
|
||||
org.nativescript.widgets.ViewHelper.setLetterspacing(this.nativeTextViewProtected, value);
|
||||
}
|
||||
|
||||
[testIDProperty.setNative](value: string): void {
|
||||
this.setAccessibilityIdentifier(this.nativeTextViewProtected, value);
|
||||
}
|
||||
@@ -493,7 +489,7 @@ export class TextBase extends TextBaseCommon {
|
||||
this.setAccessibilityIdentifier(this.nativeTextViewProtected, value);
|
||||
}
|
||||
|
||||
[maxLinesProperty.setNative](value: number) {
|
||||
[maxLinesProperty.setNative](value: CoreTypes.MaxLinesType) {
|
||||
const nativeTextViewProtected = this.nativeTextViewProtected;
|
||||
if (value <= 0) {
|
||||
nativeTextViewProtected.setMaxLines(Number.MAX_SAFE_INTEGER);
|
||||
|
||||
@@ -350,7 +350,7 @@ export class TextField extends TextFieldBase {
|
||||
}
|
||||
|
||||
if (paragraphStyle) {
|
||||
let attributedString = NSMutableAttributedString.alloc().initWithString(this.nativeViewProtected.text || '');
|
||||
const attributedString = NSMutableAttributedString.alloc().initWithString(this.nativeViewProtected.text || '');
|
||||
attributedString.addAttributeValueRange(NSParagraphStyleAttributeName, paragraphStyle, NSRangeFromString(`{0,${attributedString.length}}`));
|
||||
|
||||
this.nativeViewProtected.attributedText = attributedString;
|
||||
|
||||
@@ -70,6 +70,9 @@ public class FlexLine {
|
||||
*/
|
||||
int mItemCount;
|
||||
|
||||
/** Holds the count of the views whose visibilities are gone */
|
||||
int mGoneItemCount;
|
||||
|
||||
/**
|
||||
* @see {@link #getTotalFlexGrow()}
|
||||
*/
|
||||
@@ -151,6 +154,13 @@ public class FlexLine {
|
||||
return mItemCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the count of the views whose visibilities are not gone in this flex line.
|
||||
*/
|
||||
public int getLayoutVisibleItemCount() {
|
||||
return mItemCount - mGoneItemCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the sum of the flexGrow properties of the children included in this flex line
|
||||
*/
|
||||
|
||||
@@ -583,6 +583,7 @@ public class FlexboxLayout extends LayoutBase {
|
||||
continue;
|
||||
} else if (child.getVisibility() == View.GONE) {
|
||||
flexLine.mItemCount++;
|
||||
flexLine.mGoneItemCount++;
|
||||
addFlexLineIfLastFlexItem(i, childCount, flexLine);
|
||||
continue;
|
||||
}
|
||||
@@ -627,7 +628,7 @@ public class FlexboxLayout extends LayoutBase {
|
||||
if (isWrapRequired(widthMode, widthSize, flexLine.mMainSize,
|
||||
child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin, lp,
|
||||
i, indexInFlexLine)) {
|
||||
if (flexLine.mItemCount > 0) {
|
||||
if (flexLine.getLayoutVisibleItemCount() > 0) {
|
||||
addFlexLine(flexLine);
|
||||
}
|
||||
|
||||
@@ -681,17 +682,18 @@ public class FlexboxLayout extends LayoutBase {
|
||||
for (int i = viewIndex; i < viewIndex + flexLine.mItemCount; i++) {
|
||||
View child = getReorderedChildAt(i);
|
||||
LayoutParams lp = (LayoutParams) child.getLayoutParams();
|
||||
|
||||
if (mFlexWrap != FLEX_WRAP_WRAP_REVERSE) {
|
||||
int marginTop = flexLine.mMaxBaseline - child.getBaseline();
|
||||
marginTop = Math.max(marginTop, lp.topMargin);
|
||||
largestHeightInLine = Math.max(largestHeightInLine,
|
||||
child.getHeight() + marginTop + lp.bottomMargin);
|
||||
child.getMeasuredHeight() + marginTop + lp.bottomMargin);
|
||||
} else {
|
||||
int marginBottom = flexLine.mMaxBaseline - child.getMeasuredHeight() +
|
||||
child.getBaseline();
|
||||
marginBottom = Math.max(marginBottom, lp.bottomMargin);
|
||||
largestHeightInLine = Math.max(largestHeightInLine,
|
||||
child.getHeight() + lp.topMargin + marginBottom);
|
||||
child.getMeasuredHeight() + lp.topMargin + marginBottom);
|
||||
}
|
||||
}
|
||||
flexLine.mCrossSize = largestHeightInLine;
|
||||
@@ -745,6 +747,7 @@ public class FlexboxLayout extends LayoutBase {
|
||||
continue;
|
||||
} else if (child.getVisibility() == View.GONE) {
|
||||
flexLine.mItemCount++;
|
||||
flexLine.mGoneItemCount++;
|
||||
addFlexLineIfLastFlexItem(i, childCount, flexLine);
|
||||
continue;
|
||||
}
|
||||
@@ -790,7 +793,7 @@ public class FlexboxLayout extends LayoutBase {
|
||||
if (isWrapRequired(heightMode, heightSize, flexLine.mMainSize,
|
||||
child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin, lp,
|
||||
i, indexInFlexLine)) {
|
||||
if (flexLine.mItemCount > 0) {
|
||||
if (flexLine.getLayoutVisibleItemCount() > 0) {
|
||||
addFlexLine(flexLine);
|
||||
}
|
||||
|
||||
@@ -862,7 +865,7 @@ public class FlexboxLayout extends LayoutBase {
|
||||
}
|
||||
|
||||
private void addFlexLineIfLastFlexItem(int childIndex, int childCount, FlexLine flexLine) {
|
||||
if (childIndex == childCount - 1 && flexLine.mItemCount != 0) {
|
||||
if (childIndex == childCount - 1 && flexLine.getLayoutVisibleItemCount() != 0) {
|
||||
// Add the flex line if this item is the last item
|
||||
addFlexLine(flexLine);
|
||||
}
|
||||
@@ -1661,20 +1664,25 @@ public class FlexboxLayout extends LayoutBase {
|
||||
childLeft = paddingLeft + (width - flexLine.mMainSize) / 2f;
|
||||
childRight = width - paddingRight - (width - flexLine.mMainSize) / 2f;
|
||||
break;
|
||||
case JUSTIFY_CONTENT_SPACE_AROUND:
|
||||
if (flexLine.mItemCount != 0) {
|
||||
case JUSTIFY_CONTENT_SPACE_AROUND: {
|
||||
int visibleCount = flexLine.getLayoutVisibleItemCount();
|
||||
if (visibleCount != 0) {
|
||||
spaceBetweenItem = (width - flexLine.mMainSize)
|
||||
/ (float) flexLine.mItemCount;
|
||||
/ (float) visibleCount;
|
||||
}
|
||||
childLeft = paddingLeft + spaceBetweenItem / 2f;
|
||||
childRight = width - paddingRight - spaceBetweenItem / 2f;
|
||||
break;
|
||||
case JUSTIFY_CONTENT_SPACE_BETWEEN:
|
||||
}
|
||||
case JUSTIFY_CONTENT_SPACE_BETWEEN: {
|
||||
int visibleCount = flexLine.getLayoutVisibleItemCount();
|
||||
float denominator = visibleCount != 1 ? visibleCount - 1 : 1f;
|
||||
|
||||
childLeft = paddingLeft;
|
||||
float denominator = flexLine.mItemCount != 1 ? flexLine.mItemCount - 1 : 1f;
|
||||
spaceBetweenItem = (width - flexLine.mMainSize) / denominator;
|
||||
childRight = width - paddingRight;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new IllegalStateException(
|
||||
"Invalid justifyContent is set: " + mJustifyContent);
|
||||
@@ -1878,20 +1886,25 @@ public class FlexboxLayout extends LayoutBase {
|
||||
childTop = paddingTop + (height - flexLine.mMainSize) / 2f;
|
||||
childBottom = height - paddingBottom - (height - flexLine.mMainSize) / 2f;
|
||||
break;
|
||||
case JUSTIFY_CONTENT_SPACE_AROUND:
|
||||
if (flexLine.mItemCount != 0) {
|
||||
case JUSTIFY_CONTENT_SPACE_AROUND: {
|
||||
int visibleCount = flexLine.getLayoutVisibleItemCount();
|
||||
if (visibleCount != 0) {
|
||||
spaceBetweenItem = (height - flexLine.mMainSize)
|
||||
/ (float) flexLine.mItemCount;
|
||||
/ (float) visibleCount;
|
||||
}
|
||||
childTop = paddingTop + spaceBetweenItem / 2f;
|
||||
childBottom = height - paddingBottom - spaceBetweenItem / 2f;
|
||||
break;
|
||||
case JUSTIFY_CONTENT_SPACE_BETWEEN:
|
||||
}
|
||||
case JUSTIFY_CONTENT_SPACE_BETWEEN: {
|
||||
int visibleCount = flexLine.getLayoutVisibleItemCount();
|
||||
float denominator = visibleCount != 1 ? visibleCount - 1 : 1f;
|
||||
|
||||
childTop = paddingTop;
|
||||
float denominator = flexLine.mItemCount != 1 ? flexLine.mItemCount - 1 : 1f;
|
||||
spaceBetweenItem = (height - flexLine.mMainSize) / denominator;
|
||||
childBottom = height - paddingBottom;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new IllegalStateException(
|
||||
"Invalid justifyContent is set: " + mJustifyContent);
|
||||
@@ -2085,6 +2098,11 @@ public class FlexboxLayout extends LayoutBase {
|
||||
FlexLine flexLine = mFlexLines.get(i);
|
||||
for (int j = 0; j < flexLine.mItemCount; j++) {
|
||||
View view = getReorderedChildAt(currentViewIndex);
|
||||
|
||||
if (view == null || view.getVisibility() == View.GONE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
LayoutParams lp = (LayoutParams) view.getLayoutParams();
|
||||
|
||||
// Judge if the beginning or middle divider is needed
|
||||
@@ -2165,6 +2183,11 @@ public class FlexboxLayout extends LayoutBase {
|
||||
// Draw horizontal dividers if needed
|
||||
for (int j = 0; j < flexLine.mItemCount; j++) {
|
||||
View view = getReorderedChildAt(currentViewIndex);
|
||||
|
||||
if (view == null || view.getVisibility() == View.GONE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
LayoutParams lp = (LayoutParams) view.getLayoutParams();
|
||||
|
||||
// Judge if the beginning or middle divider is needed
|
||||
@@ -2332,11 +2355,20 @@ public class FlexboxLayout extends LayoutBase {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the flex lines composing this flex container. This method returns an unmodifiable
|
||||
* list. Thus any changes of the returned list are not supported.
|
||||
* @return the flex lines composing this flex container. This method returns a copy of the
|
||||
* original list excluding a dummy flex line (flex line that doesn't have any flex items in it
|
||||
* but used for the alignment along the cross axis).
|
||||
* Thus any changes of the returned list are not reflected to the original list.
|
||||
*/
|
||||
public List<FlexLine> getFlexLines() {
|
||||
return Collections.unmodifiableList(mFlexLines);
|
||||
List<FlexLine> result = new ArrayList<>(mFlexLines.size());
|
||||
for (FlexLine flexLine : mFlexLines) {
|
||||
if (flexLine.getLayoutVisibleItemCount() == 0) {
|
||||
continue;
|
||||
}
|
||||
result.add(flexLine);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2535,7 +2567,7 @@ public class FlexboxLayout extends LayoutBase {
|
||||
|
||||
private boolean allFlexLinesAreDummyBefore(int flexLineIndex) {
|
||||
for (int i = 0; i < flexLineIndex; i++) {
|
||||
if (mFlexLines.get(i).mItemCount > 0) {
|
||||
if (mFlexLines.get(i).getLayoutVisibleItemCount() > 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -2554,7 +2586,7 @@ public class FlexboxLayout extends LayoutBase {
|
||||
}
|
||||
|
||||
for (int i = flexLineIndex + 1; i < mFlexLines.size(); i++) {
|
||||
if (mFlexLines.get(i).mItemCount > 0) {
|
||||
if (mFlexLines.get(i).getLayoutVisibleItemCount() > 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user