Skip to content

Comments

[iOS] Fix infinite layout cycle when both parent and child views respond to SafeArea#32797

Open
Tamilarasan-Paranthaman wants to merge 5 commits intodotnet:mainfrom
Tamilarasan-Paranthaman:iOS-SafeArea-Adjustments
Open

[iOS] Fix infinite layout cycle when both parent and child views respond to SafeArea#32797
Tamilarasan-Paranthaman wants to merge 5 commits intodotnet:mainfrom
Tamilarasan-Paranthaman:iOS-SafeArea-Adjustments

Conversation

@Tamilarasan-Paranthaman
Copy link
Member

@Tamilarasan-Paranthaman Tamilarasan-Paranthaman commented Nov 21, 2025

Note

Are you waiting for the changes in this PR to be merged?
It would be very helpful if you could test the resulting artifacts from this PR and let us know in a comment if this change resolves your issue. Thank you!

Root Cause of the Issue:

  • This infinite loop appears to occur due to the combination of auto sizing calculations in the grid and SafeArea adjustments, where both the parent and child grids continuously recalculate their layouts.

  • In the user provided sample, there are two Grids (parent and child), and the default SafeArea handling behavior for a Grid is container. As a result, both the parent and child apply SafeArea logic concurrently, which can lead to the loop, particularly when the view is TranslateTo inside and outside the SafeArea region at runtime.

Description of Change:

  • SafeArea calculations are now processed only if the parent is not already handling SafeArea adjustments. Since the parent grid has already moved the content above the SafeArea, there is no need for the child controls to reapply the SafeArea logic.

Issues Fixed

Fixes #32586
Fixes #33595

Screenshot

Before Fix After Fix
Before-Fix.mov.mov
After-Fix.mov

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes an infinite layout update cycle on iOS that occurs when using TranslateToAsync with SafeArea adjustments. The issue was caused by both parent and child views in a nested Grid hierarchy applying SafeArea logic concurrently, leading to continuous layout recalculations when views are translated in and out of the SafeArea region.

Key Changes

  • Introduced IsParentHandlingSafeArea() method to check if a parent view is already applying safe area adjustments
  • Modified safe area application logic to skip adjustments when a parent is already handling them
  • Added UI test to verify the fix works correctly

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.

File Description
src/Core/src/Platform/iOS/MauiView.cs Adds parent safe area check to prevent duplicate SafeArea adjustments in nested views
src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue32586.cs NUnit test that verifies layout responsiveness with TranslateToAsync and SafeArea
src/Controls/tests/TestCases.HostApp/Issues/Issue32586.cs Test page reproducing the infinite layout cycle scenario with nested grids and animations

Copy link
Member

@jfversluis jfversluis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please address the comment: https://github.com/dotnet/maui/pull/32797/files#r2560134946

We don't want this to cause a performance hit

@jfversluis jfversluis added the s/pr-needs-author-input PR needs an update from the author label Nov 27, 2025
@Tamilarasan-Paranthaman
Copy link
Member Author

Please address the comment: https://github.com/dotnet/maui/pull/32797/files#r2560134946

We don't want this to cause a performance hit

@jfversluis , yes, I have already tested different cache based approaches on my side. Unfortunately, none of them worked in all edge cases. For example, when the parent’s SafeAreaEdges is reset to None at runtime, the behavior is still not as expected. In that scenario, we would need to check the other child views in the hierarchy as well. I will check if I can find a reliable solution for this scenario.

@jfversluis jfversluis marked this pull request as draft November 27, 2025 15:26
@jfversluis
Copy link
Member

Converting to draft while its still being worked on

@karthikraja-arumugam karthikraja-arumugam added the community ✨ Community Contribution label Dec 4, 2025
@dotnet-policy-service dotnet-policy-service bot added the stale Indicates a stale issue/pr and will be closed soon label Dec 14, 2025
@PureWeen PureWeen removed the stale Indicates a stale issue/pr and will be closed soon label Dec 14, 2025
@dotnet-policy-service
Copy link
Contributor

Hi @@Tamilarasan-Paranthaman.
It seems you haven't touched this PR for the last two weeks. To avoid accumulating old PRs, we're marking it as stale. As a result, it will be closed if no further activity occurs within 4 days of this comment. You can learn more about our Issue Management Policies here.

@sheiksyedm
Copy link
Contributor

/rebase

@rmarinho
Copy link
Member

rmarinho commented Feb 8, 2026

🤖 AI Summary

📊 Expand Full Review
🔍 Pre-Flight — Context & Validation
📝 Review SessionAdded test cases and improved the fix · ed28c5e

Issue: #32586 - Layout issue using TranslateToAsync causes infinite property changed cycle on iOS
Secondary Issue: #33595 - iOS 18.6 crashing on navigating to a ContentPage with Padding + Grid RowDefinitions Star,Auto + ScrollView on row 0
Platforms Affected: iOS only (confirmed working on Android)
Regression: Yes - worked in .NET 9 (9.0.120 SR12), broken in .NET 10 (10.0.10)
Milestone: .NET 10 SR5

Issue Summary

After upgrading to .NET 10, using TranslateToAsync with nested Grid layouts where both parent and child apply SafeArea logic (default = Container) causes an infinite layout update cycle, deadlocking the UI. Root cause traced to PR #30629 (SafeArea changes).

Secondary issue: iOS 18.6 crashes/freezes when navigating to ContentPage with Padding set and Grid with RowDefinitions="*,Auto" containing ScrollView on row 0. Same root cause.

Files Changed

Fix files:

  • src/Core/src/Platform/iOS/MauiView.cs (+29/-1) - Adds IsParentHandlingSafeArea() with caching

Test files:

  • src/Controls/tests/TestCases.HostApp/Issues/Issue32586.cs (+237) - Host app test page
  • src/Controls/tests/TestCases.HostApp/Issues/Issue33595.cs (+112) - Host app test page
  • src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue32586.cs (+84) - NUnit tests
  • src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue33595.cs (+33) - NUnit test

Test type: UI Tests

PR Discussion Summary

Reviewer Feedback Status
copilot-pull-request-reviewer Wrong comment "Create TestButton" should be "Create TestLabel" Resolved
copilot-pull-request-reviewer Comment says "deadlock" but should say "infinite layout update cycle" Resolved
copilot-pull-request-reviewer IsParentHandlingSafeArea() nitpick: consider caching Addressed in latest commit
jfversluis CHANGES_REQUESTED: Performance concern about hierarchy walk Addressed - caching added in latest commit

Notable: jfversluis's CHANGES_REQUESTED was about performance (no caching). The latest commit (ed28c5e) addresses this by adding _parentHandlesSafeArea nullable bool field with proper cache invalidation in MovedToWindow() and SafeAreaInsetsDidChange().

Fix Candidates

# Source Approach Test Result Files Changed Notes
PR PR #32797 Skip SafeArea in child if parent already handles SafeArea - IsParentHandlingSafeArea() with caching PASS (Gate) MauiView.cs (+29/-1) Original PR - includes caching

🚦 Gate — Test Verification
📝 Review SessionAdded test cases and improved the fix · ed28c5e

Result PASSED:
Platform: ios (iPhone 11 Pro Simulator, iossimulator-arm64)
Mode: Full Verification
Test Filter: Issue32586

  • Tests FAIL without fix
  • Tests PASS with fix

Fix files verified:

  • src/Core/src/Platform/iOS/MauiView.cs

🔧 Fix — Analysis & Comparison
📝 Review SessionAdded test cases and improved the fix · ed28c5e

Fix Candidates

# Source Approach Test Result Files Changed Notes
PR PR #32797 Skip SafeArea in child if parent already handles SafeArea - IsParentHandlingSafeArea() with _parentHandlesSafeArea caching PASS (Gate) MauiView.cs (+29/-1) Original PR fix
1 try-fix (prior session) Layout epoch coordination BLOCKED MauiView.cs Simulator version mismatch
2 try-fix (prior session) Thread-static layout depth counter FAIL MauiView.cs UIKit doesn't run child LayoutSubviews synchronously within parent
3 try-fix (prior session) SafeArea owner propagation (downward) BLOCKED MauiView.cs Simulator version
4 try-fix (prior session) Debounce SafeArea updates with per-view generation counter PASS MauiView.cs (+20/-3) Generation counter incremented in SafeAreaInsetsDidChange(). Simpler than PR (+20/-3 vs +29/-1), more robust to runtime changes
5 try-fix (prior session) Guard InvalidateAncestorsMeasures with _hasInvalidatedAncestorsForSafeArea boolean; reset on genuine value changes FAIL MauiView.cs UIKit's SafeAreaInsets genuinely change each cycle; value-based dedup cannot break this cycle
6 try-fix (prior session) Parent safe-area delta (subtract parent computed _safeArea from child) FAIL MauiView.cs Issue32586 still fails; delta padding does not stop parent/child invalidation loop
7 try-fix (prior session) Inset-equality guard (skip adjustments when parent/child SafeAreaInsets match) FAIL MauiView.cs VerifyRuntimeSafeAreaEdgesChange fails; SafeAreaEdges=None doesn't move content because UIKit insets remain equal
8 try-fix (prior session) Safe area ancestor invalidation guard - boolean gates entire safe-area-changed block in LayoutSubviews FAIL MauiView.cs Multiple entry points (InvalidateMeasure also sets _safeAreaInvalidated=true); single boolean cannot break it

Note: Current session try-fix attempts blocked by API rate limiting. Results imported from prior complete agent session (commit ed28c5e).

Root Cause Analysis

In .NET 10 (PR #30629), SafeArea handling was refactored so each MauiView independently determines whether to apply SafeArea adjustments in ValidateSafeArea(). When nested views (e.g., parent Grid + child Grid) both have SafeArea=Container (the default), each view's SafeArea-triggered layout change calls InvalidateAncestorsMeasures(), which causes the other view to re-layout. Since UIKit recalculates SafeAreaInsets on each layout pass (values genuinely change as frames adjust), value-based deduplication cannot break the cycle.

Key Technical Insight: UIKit's LayoutSubviews() is asynchronous - child layout runs AFTER parent completes. Any temporal/execution-scoped approach (flags, try-finally, depth counters) fails because there's no temporal overlap between parent and child layout passes. Only approaches with persistent state (cached bools, generation counters) work.

Exhausted: Yes (imported from prior complete session; all viable approaches were tested)
Selected Fix: PR's fix - The hierarchy walk + parent check approach directly addresses the root cause by having child views defer SafeArea handling to their parent when the parent already handles it. While the generation counter (candidate #4) is simpler, the PR's approach is semantically clearer (explicitly encodes the "parent handles SafeArea" relationship) and addresses the root cause rather than just debouncing the symptom.


📋 Report — Final Recommendation
📝 Review SessionAdded test cases and improved the fix · ed28c5e

Final Recommendation: APPROVE

Summary

PR #32797 fixes an iOS infinite layout cycle regression introduced in .NET 10 (PR #30629). When nested views both have SafeArea=Container (the default), each view's SafeArea-triggered layout update calls InvalidateAncestorsMeasures(), causing the sibling/parent to re-layout, creating an infinite cycle that deadlocks the UI.

Title Assessment

Current: [iOS] Fix infinite layout cycle when both parent and child views respond to SafeArea
Verdict Accurate platform prefix, describes the behavior fix clearly, searchable.Good :

Description Assessment

Verdict Has NOTE block, root cause, description of change, issues fixed, screenshots.Good :

Minor suggestion: The description could be enhanced with:

  • A "What NOT to Do" note about temporal/execution-scoped approaches (flags, depth counters) failing because UIKit's LayoutSubviews is asynchronous
  • Noting the cache invalidation strategy for runtime SafeAreaEdges changes

Root Cause

In .NET 10 (PR #30629), each MauiView independently determines whether to apply SafeArea adjustments in ValidateSafeArea(). When nested views (e.g., parent Grid + child Grid) both have SafeArea=Container (the default), each view's SafeArea-triggered layout change calls InvalidateAncestorsMeasures(), causing the other view to re-layout. Since UIKit recalculates SafeAreaInsets on each layout pass (values genuinely change as frames adjust), value-based deduplication cannot break the cycle. This creates an infinite layout loop that deadlocks the UI.

Key insight: UIKit's LayoutSubviews() is child layout runs AFTER parent completes. Any temporal/execution-scoped approach (flags, try-finally, depth counters) fails because there's no temporal overlap between parent and child layout passes. Only approaches with persistent state (cached bools, generation counters) work.asynchronous

Fix Analysis

The PR adds IsParentHandlingSafeArea() in MauiView.cs which:

  1. Walks up the iOS view hierarchy to find a parent MauiView with _appliesSafeAreaAdjustments=true and implementing ISafeAreaView/ISafeAreaView2
  2. If such a parent exists, the child skips SafeArea adjustments, breaking the infinite cycle
  3. Caches the result in _parentHandlesSafeArea (nullable bool)
  4. Invalidates cache in SafeAreaInsetsDidChange() and MovedToWindow() for runtime correctness

The fix directly addresses the root cause by having child views defer SafeArea handling to their parent. The caching addresses jfversluis's performance concern (hierarchy walk only on first check per layout context).

Code Review Findings

Looks Good

  • _parentHandlesSafeArea cache uses nullable bool pattern (same as existing _scrollViewDescendant) - consistent with codebase
  • Cache invalidation on SafeAreaInsetsDidChange() and MovedToWindow() are correct trigger points
  • XML documentation on IsParentHandlingSafeArea() is clear and helpful
  • Test covers both the animation scenario (Issue32586) and navigation crash scenario (Issue33595)
  • VerifyRuntimeSafeAreaEdgesChange test validates the runtime SafeAreaEdges toggle behavior
  1. Comment accuracy in Issue32586.cs line 182: Still says // This causes deadlock on iOS .NET copilot reviewer flagged this as misleading (it's an infinite layout cycle, not a deadlock). This thread shows as Resolved but the comment wasn't updated in the code.10 ####
  2. Issue33595.cs indentation: Uses 4-space indentation while rest of repo uses tabs. Minor but inconsistent.
  3. Issue32586.cs #if IOS || ANDROID: The test is Android-tagged but the fix is iOS-only. Android will run the test but won't reproduce the bug (confirming no regression on Android). This is acceptable but the [Issue] attribute specifies PlatformAffected.iOS.

Gate Result

Tests FAIL without fix, PASS with fix (iOS, iPhone 11 Pro Simulator)PASSED

Alternative Fix Considered

An independent generation-counter approach (try-fix #4 from prior session) also passes all tests with a simpler diff (+20/-3 vs +29/-1). However, the PR's approach is semantically clearer and has been reviewed by the team. The generation counter is a viable alternative if the hierarchy walk proves problematic in practice.


📋 Expand PR Finalization Review
Title: ✅ Good

Current: [iOS] Fix infinite layout cycle when both parent and child views respond to SafeArea

Description: ✅ Good

Description needs updates. See details below.

✨ Suggested PR Description

[!NOTE]
Are you waiting for the changes in this PR to be merged?
It would be very helpful if you could test the resulting artifacts from this PR and let us know in a comment if this change resolves your issue. Thank you!

Root Cause

On iOS, when both a parent and child MauiView implement ISafeAreaView or ISafeAreaView2 with SafeAreaEdges.Container (the default), both views independently call ValidateSafeArea() and both set _appliesSafeAreaAdjustments = true. This leads to both views applying padding adjustments to move content out of the safe area. When one of those views is involved in an animation (e.g., TranslateToAsync), the competing safe area recalculations create a feedback loop — each layout pass triggered by the animation causes both views to re-evaluate and re-apply safe area, which triggers another layout pass, causing an infinite cycle that deadlocks the UI.

This affected at least two scenarios:

  1. Layout issue using TranslateToAsync causes infinite property changed cycle on iOS #32586 – A Grid containing a VerticalStackLayout, with a footer view animated via TranslateToAsync, froze the UI indefinitely.
  2. [net10] iOS 18.6 crashing on navigating to a ContentPage with Padding set and Content set to a <Grid RowDefinitions="*,Auto"> with ScrollView on row 0 #33595 – A ContentPage with Padding set containing a Grid with RowDefinitions="*,Auto" and a ScrollView in row 0 caused the app to freeze/crash on iOS 18.6 with .NET 10.

Both issues are regressions in .NET 10 (worked in .NET 9 / 9.0.120 SR12 and earlier).

Description of Change

src/Core/src/Platform/iOS/MauiView.cs

  • Added new bool? _parentHandlesSafeArea cached field (nullable, following the same pattern as _scrollViewDescendant).
  • Added new IsParentHandlingSafeArea() method that walks the view hierarchy upward to find any ancestor MauiView that already has _appliesSafeAreaAdjustments = true and implements ISafeAreaView or ISafeAreaView2.
  • Modified ValidateSafeArea() so that _appliesSafeAreaAdjustments is only set to true when no parent is already applying safe area adjustments: _appliesSafeAreaAdjustments = !parentHandlingSafeArea && RespondsToSafeArea() && !_safeArea.IsEmpty
  • Cache (_parentHandlesSafeArea) is invalidated in:
    • SafeAreaInsetsDidChange() — when the device safe area insets change (e.g., rotation, keyboard)
    • MovedToWindow() — when the view is added to or removed from the view hierarchy

Tests (src/Controls/tests/)

  • Added TestCases.HostApp/Issues/Issue32586.cs — reproduces the TranslateToAsync infinite cycle; includes toggle buttons for parent/child SafeAreaEdges to test runtime behavior.
  • Added TestCases.HostApp/Issues/Issue33595.cs — reproduces the navigation freeze with Grid+ScrollView+Padding.
  • Added TestCases.Shared.Tests/Tests/Issues/Issue32586.cs — two UI tests: animation works correctly, SafeAreaEdges toggling at runtime works without loop.
  • Added TestCases.Shared.Tests/Tests/Issues/Issue33595.cs — navigation to the affected page succeeds without freeze.

Key Technical Details

Types involved:

  • MauiView — the base iOS platform view in src/Core/src/Platform/iOS/
  • ISafeAreaView — legacy safe area interface (IgnoreSafeArea property)
  • ISafeAreaView2 — newer safe area interface with SafeAreaEdges/GetSafeAreaRegionsForEdge()
  • _appliesSafeAreaAdjustments — internal bool flag indicating this view is actively applying safe area padding

Key invariant: In a view hierarchy, at most one ancestor MauiView applies safe area adjustments. The topmost view that implements ISafeAreaView/ISafeAreaView2 and responds to safe area takes ownership; descendants skip their adjustments.

Caching strategy: _parentHandlesSafeArea is a bool? nullable field initialized to null (not yet computed). It is populated on first call to IsParentHandlingSafeArea() and cleared when the hierarchy or safe area changes. This follows the same pattern as _scrollViewDescendant.

Issues Fixed

Fixes #32586
Fixes #33595

Platforms Tested

  • iOS
  • Android (fix is iOS-specific; platform layer code is iOS-only)
  • Windows
  • Mac Catalyst
Code Review: ⚠️ Issues Found

Code Review — PR #32797

🔴 Critical Issues

None.


🟡 Suggestions

1. Wrong Platform Guard in Issue32586.cs UI Test

File: src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue32586.cs
Line: 1

#if IOS || ANDROID

Problem: The || ANDROID is incorrect. The bug (#32586) is iOS-only — it is a regression in MauiView.cs on iOS's platform layer. The SafeAreaEdges concept and MauiView's ValidateSafeArea() only apply to iOS. Running this test on Android would test behavior that doesn't exist there, and the assertions (e.g., verifying TopMarker.Y > 0 due to safe area inset) would produce meaningless or incorrect results on Android.

Additionally, the related fix in Issue33595.cs is correctly guarded with #if IOS only.

Recommendation: Change to:

#if IOS

2. Misleading Comment in Issue32586.cs HostApp

File: src/Controls/tests/TestCases.HostApp/Issues/Issue32586.cs
Line: ~182

// This causes deadlock on iOS .NET 10
await FooterView.TranslateToAsync(0, 0, AnimationDuration, Easing.CubicInOut);

Problem: The comment says "deadlock" but the actual issue is an infinite layout cycle / property changed loop. A deadlock implies mutual thread blocking, which is not what occurs here. The PR description itself correctly identifies this as "an infinite property changed cycle". This comment was flagged during review (as PRRT_kwDOD6PVWM5jdllo) but appears unresolved in the current code.

Recommendation:

// Previously caused an infinite layout update cycle on iOS .NET 10
await FooterView.TranslateToAsync(0, 0, AnimationDuration, Easing.CubicInOut);

3. Redundant Interface Check in IsParentHandlingSafeArea()

File: src/Core/src/Platform/iOS/MauiView.cs
Lines: 401–403

_parentHandlesSafeArea = this.FindParent(x => x is MauiView mv
    && mv._appliesSafeAreaAdjustments
    && mv.View is ISafeAreaView or ISafeAreaView2) is not null;

Problem: The condition mv.View is ISafeAreaView or ISafeAreaView2 is redundant. mv._appliesSafeAreaAdjustments is only ever set to true when RespondsToSafeArea() returns a non-empty SafeAreaPadding, which in turn only happens when View is ISafeAreaView2 or View is ISafeAreaView. So checking the interface again is unnecessary.

Recommendation:

_parentHandlesSafeArea = this.FindParent(x => x is MauiView mv
    && mv._appliesSafeAreaAdjustments) is not null;

This is cleaner and more consistent with the encapsulation intent of _appliesSafeAreaAdjustments.


4. Cache Invalidation May Be Incomplete for Runtime SafeAreaEdges Changes

File: src/Core/src/Platform/iOS/MauiView.cs

Problem: _parentHandlesSafeArea is invalidated in SafeAreaInsetsDidChange() and MovedToWindow(). However, when a parent's SafeAreaEdges property changes at runtime (as tested in VerifyRuntimeSafeAreaEdgesChange()), neither of those events fires on the child. The child's _parentHandlesSafeArea cache may remain stale, returning an incorrect result until the next safe area insets change or view hierarchy change.

In practice, changing SafeAreaEdges triggers a layout invalidation, which leads to SafeAreaInsetsDidChange() being called on descendants (because layout recalculation causes the system to re-evaluate safe area insets). If this happens reliably in practice, the cache is effectively always fresh. The test VerifyRuntimeSafeAreaEdgesChange() verifies this scenario works.

Recommendation: Verify (or document) that changing SafeAreaEdges on a parent reliably triggers SafeAreaInsetsDidChange() on children. If there are edge cases where it doesn't (e.g., when the view is off-screen), consider also invalidating _parentHandlesSafeArea when the parent hierarchy is traversed and a stale result would matter.

This is a low-risk concern since the test covers the runtime toggle scenario.


5. Missing Newline at End of File

File: src/Controls/tests/TestCases.HostApp/Issues/Issue32586.cs

The file is missing a newline at the end (\ No newline at end of file in the diff). Minor style issue.


✅ Looks Good


@Tamilarasan-Paranthaman Tamilarasan-Paranthaman changed the title [iOS] Fix infinite update cycle in layout when applying TranslateToAsync with SafeArea [iOS] Fix infinite layout cycle when both parent and child views respond to SafeArea Feb 9, 2026
@Tamilarasan-Paranthaman Tamilarasan-Paranthaman added the area-safearea Issues/PRs that have to do with the SafeArea functionality label Feb 9, 2026
@PureWeen
Copy link
Member

/azp run maui-pr-uitests, maui-pr-devicetests

@azure-pipelines
Copy link

Azure Pipelines successfully started running 2 pipeline(s).

PureWeen added a commit that referenced this pull request Feb 11, 2026
Two fixes:
1. post-ai-summary-comment.ps1: Remove legacy stdin reader ($input |
   Out-String) that blocks forever in non-interactive CI contexts when
   no state file is found.
2. ci-copilot.yml: Add state file existence check before calling the
   script (skip gracefully if missing), and add timeoutInMinutes: 5
   as a safety net.

Root cause: Build 13284089 (iOS, PR #32797) timed out at 180 min
because the fallback step hung for 2+ hours reading from stdin.
@jonathanmourtadahqv
Copy link

jonathanmourtadahqv commented Feb 11, 2026

We have an app that after upgrading to .net10 have had multiple layout cycle problems on iOS. None of these issues existed with .net9.

We have experienced this as pages just being blank because of infinite layout loops when navigating to them. If i press pause when debugging I can see that the stacktrace always starts with something like MauiView.__Registrar_Callbacks__.callback_918_Microsoft_Maui_Platform_MauiView_LayoutSubviews().

The workaround have been all kinds of stuff.

  • Setting heightrequest on images
  • Removing custom fonts on labels
  • Setting FontAutoScalingEnabled=false on labels
  • Changing grid column definitions from auto to fixed sizes.

The font problems seems to happen if the user set a text size in ios settings -> display & brightness that is not the default. We have one page which has had almost all of this problems. We have this page locked in landscape mode and use SafeAreaEdges.None on all the grids.

I have a hard time figuring out what is actually causing this. Right now to find out which element is the problem I have to remove elements until it works

I have two layout cycle problems right now and I've tried this PR but it didn't solve it.

PureWeen added a commit that referenced this pull request Feb 12, 2026
Two fixes:
1. post-ai-summary-comment.ps1: Remove legacy stdin reader ($input |
   Out-String) that blocks forever in non-interactive CI contexts when
   no state file is found.
2. ci-copilot.yml: Add state file existence check before calling the
   script (skip gracefully if missing), and add timeoutInMinutes: 5
   as a safety net.

Root cause: Build 13284089 (iOS, PR #32797) timed out at 180 min
because the fallback step hung for 2+ hours reading from stdin.
kubaflo pushed a commit that referenced this pull request Feb 12, 2026
Two fixes:
1. post-ai-summary-comment.ps1: Remove legacy stdin reader ($input |
   Out-String) that blocks forever in non-interactive CI contexts when
   no state file is found.
2. ci-copilot.yml: Add state file existence check before calling the
   script (skip gracefully if missing), and add timeoutInMinutes: 5
   as a safety net.

Root cause: Build 13284089 (iOS, PR #32797) timed out at 180 min
because the fallback step hung for 2+ hours reading from stdin.
PureWeen added a commit that referenced this pull request Feb 12, 2026
…tion counter

When both a parent and child view respond to SafeArea (both have SafeAreaEdges = Container),
an infinite layout cycle occurs: each view's layout change triggers the other to re-validate,
creating an endless loop that freezes the app.

Root cause: Both views apply SafeArea padding independently. Each layout pass invalidates
ancestors, which triggers another layout pass, ad infinitum.

Previous approach (PR #32797): Check if parent handles SafeArea via hierarchy walk. Problem:
This silences ALL child SafeArea edges when parent handles ANY edge, breaking nested SafeArea
scenarios where parent handles top and child independently handles bottom.

This fix: Use a generation counter incremented on genuine SafeAreaInsetsDidChange events.
Each view tracks the last generation where it invalidated ancestors. If already invalidated
for current generation, skip re-invalidation and just arrange.

Benefits:
- Breaks the cycle: within a single SafeArea change event, each view only invalidates once
- Preserves correct behavior: both parent and child can still apply their own SafeArea edges
- Simpler logic: no hierarchy walking, just atomic counter check

Test cases (Issue32586, Issue33595):
- Nested Grid + VerticalStackLayout with SafeArea=Container
- TranslateToAsync animation that previously triggered infinite cycle
- Runtime SafeAreaEdges toggling

Fixes #32586
Fixes #33595
@rmarinho rmarinho added s/agent-approved AI agent recommends approval - PR fix is correct and optimal s/agent-fix-win AI found a better alternative fix than the PR s/agent-reviewed PR was reviewed by AI agent workflow (full 4-phase review) labels Feb 18, 2026
github-actions bot pushed a commit that referenced this pull request Feb 19, 2026
…tion counter

When both a parent and child view respond to SafeArea (both have SafeAreaEdges = Container),
an infinite layout cycle occurs: each view's layout change triggers the other to re-validate,
creating an endless loop that freezes the app.

Root cause: Both views apply SafeArea padding independently. Each layout pass invalidates
ancestors, which triggers another layout pass, ad infinitum.

Previous approach (PR #32797): Check if parent handles SafeArea via hierarchy walk. Problem:
This silences ALL child SafeArea edges when parent handles ANY edge, breaking nested SafeArea
scenarios where parent handles top and child independently handles bottom.

This fix: Use a generation counter incremented on genuine SafeAreaInsetsDidChange events.
Each view tracks the last generation where it invalidated ancestors. If already invalidated
for current generation, skip re-invalidation and just arrange.

Benefits:
- Breaks the cycle: within a single SafeArea change event, each view only invalidates once
- Preserves correct behavior: both parent and child can still apply their own SafeArea edges
- Simpler logic: no hierarchy walking, just atomic counter check

Test cases (Issue32586, Issue33595):
- Nested Grid + VerticalStackLayout with SafeArea=Container
- TranslateToAsync animation that previously triggered infinite cycle
- Runtime SafeAreaEdges toggling

Fixes #32586
Fixes #33595
@kubaflo kubaflo added s/agent-fix-lose AI could not beat the PR fix - PR is the best among all candidates s/agent-fix-pr-picked AI could not beat the PR fix - PR is the best among all candidates and removed s/agent-fix-win AI found a better alternative fix than the PR s/agent-fix-lose AI could not beat the PR fix - PR is the best among all candidates labels Feb 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-safearea Issues/PRs that have to do with the SafeArea functionality community ✨ Community Contribution partner/syncfusion Issues / PR's with Syncfusion collaboration platform/ios s/agent-approved AI agent recommends approval - PR fix is correct and optimal s/agent-fix-pr-picked AI could not beat the PR fix - PR is the best among all candidates s/agent-reviewed PR was reviewed by AI agent workflow (full 4-phase review)

Projects

None yet

8 participants