From bf8722861b785a1125255b00438b40d9ddcf1ca7 Mon Sep 17 00:00:00 2001 From: Dimitris - Rafail Katsampas Date: Sun, 17 May 2026 21:42:56 +0300 Subject: [PATCH 1/2] fix(ios): Correct layout validity status during layout changed event --- .../src/ui/view/view-tests-layout-event.ts | 17 +++++++++++++++++ packages/core/ui/core/view/index.ios.ts | 8 +++----- packages/core/ui/core/view/view-common.ts | 9 +-------- 3 files changed, 21 insertions(+), 13 deletions(-) diff --git a/apps/automated/src/ui/view/view-tests-layout-event.ts b/apps/automated/src/ui/view/view-tests-layout-event.ts index df742e2c79..fda3045cc4 100644 --- a/apps/automated/src/ui/view/view-tests-layout-event.ts +++ b/apps/automated/src/ui/view/view-tests-layout-event.ts @@ -18,6 +18,23 @@ export function test_event_LayoutChanged_GetActualSize() { helper.do_PageTest_WithStackLayout_AndButton(test); } +export function test_event_LayoutChanged_IsLayoutValid() { + const test = function (views: Array) { + let buttonLayoutChanged = false; + let expectedValidResult; + + views[1].on(View.layoutChangedEvent, (args) => { + expectedValidResult = (args.object as View).isLayoutValid; + buttonLayoutChanged = true; + }); + + TKUnit.waitUntilReady(() => buttonLayoutChanged, 5); + TKUnit.assertFalse(expectedValidResult); + }; + + helper.do_PageTest_WithStackLayout_AndButton(test); +} + export function test_event_LayoutChanged_Listeners() { const test = function (views: Array) { let buttonLayoutChanged = false; diff --git a/packages/core/ui/core/view/index.ios.ts b/packages/core/ui/core/view/index.ios.ts index 85b4c8baaf..25a040286e 100644 --- a/packages/core/ui/core/view/index.ios.ts +++ b/packages/core/ui/core/view/index.ios.ts @@ -95,8 +95,7 @@ export class View extends ViewCommon { public measure(widthMeasureSpec: number, heightMeasureSpec: number): void { const measureSpecsChanged = this._setCurrentMeasureSpecs(widthMeasureSpec, heightMeasureSpec); - const forceLayout = (this._privateFlags & PFLAG_FORCE_LAYOUT) === PFLAG_FORCE_LAYOUT; - if (this.nativeViewProtected && (forceLayout || measureSpecsChanged)) { + if (this.nativeViewProtected && (this.isLayoutRequested || measureSpecsChanged)) { // first clears the measured dimension flag this._privateFlags &= ~PFLAG_MEASURED_DIMENSION_SET; @@ -122,7 +121,7 @@ export class View extends ViewCommon { this.layoutNativeView(left, top, right, bottom); } - const needsLayout = boundsChanged || (this._privateFlags & PFLAG_LAYOUT_REQUIRED) === PFLAG_LAYOUT_REQUIRED; + const needsLayout = boundsChanged || this.isLayoutRequired; if (needsLayout) { let position: Position; @@ -259,9 +258,8 @@ export class View extends ViewCommon { get isLayoutValid(): boolean { if (this.nativeViewProtected) { - return this._isLayoutValid; + return !this.isLayoutRequested; } - return false; } diff --git a/packages/core/ui/core/view/view-common.ts b/packages/core/ui/core/view/view-common.ts index ee5dff2014..5ba6c4205d 100644 --- a/packages/core/ui/core/view/view-common.ts +++ b/packages/core/ui/core/view/view-common.ts @@ -128,7 +128,6 @@ export abstract class ViewCommon extends ViewBase { private _measuredWidth: number; private _measuredHeight: number; - protected _isLayoutValid: boolean; private _cssType: string; private _localAnimations: Set; @@ -1009,7 +1008,7 @@ export abstract class ViewCommon extends ViewBase { //END Style property shortcuts get isLayoutValid(): boolean { - return this._isLayoutValid; + return false; } get cssType(): string { @@ -1070,11 +1069,6 @@ export abstract class ViewCommon extends ViewBase { } } - public requestLayout(): void { - this._isLayoutValid = false; - super.requestLayout(); - } - public abstract onMeasure(widthMeasureSpec: number, heightMeasureSpec: number): void; public abstract onLayout(left: number, top: number, right: number, bottom: number): void; public abstract layoutNativeView(left: number, top: number, right: number, bottom: number): void; @@ -1111,7 +1105,6 @@ export abstract class ViewCommon extends ViewBase { * Returns two booleans - the first if "boundsChanged" the second is "sizeChanged". */ _setCurrentLayoutBounds(left: number, top: number, right: number, bottom: number): { boundsChanged: boolean; sizeChanged: boolean } { - this._isLayoutValid = true; const boundsChanged: boolean = this._oldLeft !== left || this._oldTop !== top || this._oldRight !== right || this._oldBottom !== bottom; const sizeChanged: boolean = this._oldRight - this._oldLeft !== right - left || this._oldBottom - this._oldTop !== bottom - top; this._oldLeft = left; From 48befa9125bb8f007dcc395cfb195e1a129ff167 Mon Sep 17 00:00:00 2001 From: Dimitris - Rafail Katsampas Date: Sun, 17 May 2026 22:17:43 +0300 Subject: [PATCH 2/2] chore: updated a small number of automated tests to check layout flag --- apps/automated/src/ui/image/image-tests.ts | 12 ++++-------- apps/automated/src/ui/label/label-tests.ts | 6 ++---- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/apps/automated/src/ui/image/image-tests.ts b/apps/automated/src/ui/image/image-tests.ts index 20e129e235..50edc44da2 100644 --- a/apps/automated/src/ui/image/image-tests.ts +++ b/apps/automated/src/ui/image/image-tests.ts @@ -268,10 +268,8 @@ export const test_SettingImageSourceWhenSizedToParentDoesNotRequestLayout = ios( let mainPage = helper.getCurrentPage(); mainPage.content = host; - const nativeHostView = host.nativeViewProtected as UIView; - - // Check if native view layer is still marked as dirty before proceeding - TKUnit.waitUntilReady(() => host.isLoaded && nativeHostView?.layer && !nativeHostView.layer.needsLayout()); + // Check if view is loaded and layout is valid + TKUnit.waitUntilReady(() => host.isLoaded && host.isLayoutValid); let called = false; image.requestLayout = () => (called = true); @@ -290,10 +288,8 @@ export const test_SettingImageSourceWhenFixedWidthAndHeightDoesNotRequestLayout let mainPage = helper.getCurrentPage(); mainPage.content = host; - const nativeHostView = host.nativeViewProtected as UIView; - - // Check if native view layer is still marked as dirty before proceeding - TKUnit.waitUntilReady(() => host.isLoaded && nativeHostView?.layer && !nativeHostView.layer.needsLayout()); + // Check if view is loaded and layout is valid + TKUnit.waitUntilReady(() => host.isLoaded && host.isLayoutValid); let called = false; image.requestLayout = () => (called = true); diff --git a/apps/automated/src/ui/label/label-tests.ts b/apps/automated/src/ui/label/label-tests.ts index 9696aca3fe..508e0f7d87 100644 --- a/apps/automated/src/ui/label/label-tests.ts +++ b/apps/automated/src/ui/label/label-tests.ts @@ -602,10 +602,8 @@ export class LabelTest extends testModule.UITest