Skip to content

Comments

Fixed the crash on iOS when setting HeightRequest on WebView inside a ScrollView with IsVisible set to false#29022

Merged
PureWeen merged 5 commits intodotnet:inflight/currentfrom
Ahamed-Ali:fix-26795
Feb 19, 2026
Merged

Fixed the crash on iOS when setting HeightRequest on WebView inside a ScrollView with IsVisible set to false#29022
PureWeen merged 5 commits intodotnet:inflight/currentfrom
Ahamed-Ali:fix-26795

Conversation

@Ahamed-Ali
Copy link
Contributor

@Ahamed-Ali Ahamed-Ali commented Apr 16, 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

When WebView is placed inside a ScrollView (especially with IsVisible=false), the measurement pass can receive infinite constraints. The previous implementation in GetDesiredSize used widthConstraint and heightConstraint directly to initialize the width and height variables. When these constraints were infinite, the code could propagate infinite or NaN values into subsequent calculations, causing crashes on iOS during layout operations.

The regression was introduced in PR #26629.

Description of Change

Changed WebViewHandler.iOS.cs to use the measured size (size.Width and size.Height from PlatformView.SizeThatFits) instead of the constraint values when initializing the width and height variables in GetDesiredSize.

Key change:

// Before (could use infinite constraints)
var width = widthConstraint;
var height = heightConstraint;

// After (use measured size, which is always finite)
var width = size.Width;
var height = size.Height;

The subsequent validation logic (checking if width/height is 0 and falling back to constraints if valid) remains the same, ensuring backward compatibility while preventing infinite values from being used in calculations.

What NOT to Do (for future agents)

  • Don't use constraint values directly without checking for infinity - Constraints can be infinite in scrollable containers (ScrollView, ListView). Always validate constraints before using them, or prefer using measured size from the native control.
  • Don't assume constraints are always finite in GetDesiredSize - Layout containers frequently pass infinite constraints during measurement to determine intrinsic size.

Regressed PR

Issues Fixed

Fixes #26795

Platforms Tested

  • Android
  • Windows
  • iOS
  • Mac

Screenshot

Before Issue Fix After Issue Fix
WebViewCrash.mov
WebViewFix.mov
Details

@dotnet-policy-service dotnet-policy-service bot added community ✨ Community Contribution partner/syncfusion Issues / PR's with Syncfusion collaboration labels Apr 16, 2025
@Ahamed-Ali Ahamed-Ali marked this pull request as ready for review April 17, 2025 04:58
@Ahamed-Ali Ahamed-Ali requested a review from a team as a code owner April 17, 2025 04:58
@jsuarezruiz
Copy link
Contributor

/azp run MAUI-UITests-public

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

Copilot AI review requested due to automatic review settings December 9, 2025 08:26
@github-actions
Copy link
Contributor

github-actions bot commented Dec 9, 2025

🚀 Dogfood this PR with:

⚠️ WARNING: Do not do this without first carefully reviewing the code of this PR to satisfy yourself it is safe.

curl -fsSL https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.sh | bash -s -- 29022

Or

  • Run remotely in PowerShell:
iex "& { $(irm https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.ps1) } 29022"

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 addresses a crash on iOS when a WebView with HeightRequest is placed inside an invisible ScrollView. The fix modifies the GetDesiredSize method in WebViewHandler.iOS.cs to use the computed size dimensions instead of the constraint parameters directly, preventing infinite values from causing layout exceptions.

  • Fixes iOS crash when WebView with HeightRequest is inside invisible ScrollView
  • Updates GetDesiredSize to use size.Width/Height instead of widthConstraint/heightConstraint
  • Adds UI test to prevent regression

Reviewed changes

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

File Description
src/Core/src/Handlers/WebView/WebViewHandler.iOS.cs Modified GetDesiredSize to use size dimensions instead of constraints to prevent infinite value propagation
src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue26795.cs Added NUnit UI test to verify WebView doesn't crash with HeightRequest in invisible ScrollView
src/Controls/tests/TestCases.HostApp/Issues/Issue26795.cs Added test page reproducing the crash scenario with WebView inside invisible ScrollView
Comments suppressed due to low confidence (1)

src/Core/src/Handlers/WebView/WebViewHandler.iOS.cs:126

  • The logic appears incomplete. When width or height is 0 and the constraint is valid and finite (not infinite, not <= 0), the code should fall back to using the constraint value.

Currently, if size.Width is 0 but widthConstraint is a valid finite value like 300, the code will leave width as 0 instead of using the constraint. This could cause incorrect layout calculations.

Consider adding an else clause to handle the case where constraints are valid:

if (width == 0)
{
    if (widthConstraint <= 0 || double.IsInfinity(widthConstraint))
    {
        width = MinimumSize;
        set = true;
    }
    else
    {
        width = widthConstraint;
        set = true;
    }
}

And similarly for height.

			if (width == 0)
			{
				if (widthConstraint <= 0 || double.IsInfinity(widthConstraint))
				{
					width = MinimumSize;
					set = true;
				}
			}

			if (height == 0)
			{
				if (heightConstraint <= 0 || double.IsInfinity(heightConstraint))
				{
					height = MinimumSize;
					set = true;
				}
			}

Comment on lines +14 to +17
public void WebViewShouldNotCrashWithHeightRequest()
{
App.WaitForElement("Label");
}
Copy link

Copilot AI Dec 9, 2025

Choose a reason for hiding this comment

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

The test only verifies that the app doesn't crash, but doesn't validate the actual layout behavior. Consider adding assertions to verify:

  1. The WebView renders with the correct dimensions when made visible
  2. The HeightRequest is respected
  3. The layout works correctly when the ScrollView's IsVisible property is toggled

Example:

App.Tap("ToggleVisibilityButton");
App.WaitForElement("WebViewId");
var webViewRect = App.FindElement("WebViewId").GetRect();
Assert.That(webViewRect.Height, Is.GreaterThan(0));

This would provide more comprehensive coverage of the layout fix beyond just crash prevention.

Copilot uses AI. Check for mistakes.
Comment on lines +10 to +14
var webView = new WebView
{
Source = "https://en.m.wikipedia.org/wiki",
HeightRequest = 1000,
};
Copy link

Copilot AI Dec 9, 2025

Choose a reason for hiding this comment

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

Consider adding an AutomationId to the WebView to enable more comprehensive UI testing of the layout behavior:

var webView = new WebView
{
    Source = "https://en.m.wikipedia.org/wiki",
    HeightRequest = 1000,
    AutomationId = "TestWebView"
};

This would allow the test to verify that the WebView is properly sized and positioned, not just that the app doesn't crash.

Copilot uses AI. Check for mistakes.
Comment on lines +22 to +26
var scrollView = new ScrollView
{
IsVisible = false,
Content = webView
};
Copy link

Copilot AI Dec 9, 2025

Choose a reason for hiding this comment

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

Consider adding a button to toggle the ScrollView's visibility to enable more comprehensive testing:

var toggleButton = new Button
{
    Text = "Toggle Visibility",
    AutomationId = "ToggleVisibilityButton"
};
toggleButton.Clicked += (s, e) => scrollView.IsVisible = !scrollView.IsVisible;
layout.Children.Add(toggleButton);

This would allow the test to verify that the WebView layout works correctly both when initially invisible and when made visible.

Copilot uses AI. Check for mistakes.
@rmarinho
Copy link
Member

rmarinho commented Feb 14, 2026

🤖 AI Summary

📊 Expand Full Review
🔍 Pre-Flight — Context & Validation
📝 Review SessionOptimized the code · 493f5ec

Issue: #26795 - Specifying HeightRequest in Webview when wrapped by ScrollView set "invisible" causes crash in iOS
PR: #29022 - Fixed the crash on iOS when setting HeightRequest on WebView inside a ScrollView with IsVisible set to false
Author: Ahamed-Ali (community contribution)
Platform Affected: iOS (confirmed via label platform/ios)
Regression: Yes - Introduced by PR #26629, initially fixed by PR #26763 in 9.0.30, then regressed again in 9.0.50

Summary

WebView crashes on iOS with CALayerInvalidGeometry exception (CALayer position contains NaN) when:

  • WebView has HeightRequest set
  • Placed inside a ScrollView
  • ScrollView has IsVisible="False"

Error message: CALayer position contains NaN: [22 nan]

Root Cause (Per PR Description)

When WebView is placed inside a ScrollView, the height constraint can become infinite. The original code was using constraints directly, which could propagate infinite values, causing layout issues and NaN exceptions.

Files Changed

Fix files:

  • src/Core/src/Handlers/WebView/WebViewHandler.iOS.cs (+4, -4)

Test files:

  • src/Controls/tests/TestCases.HostApp/Issues/Issue26795.cs (+31) - UI test page
  • src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue26795.cs (+18) - UI test

Test type: UI Tests

PR Discussion Summary

Review feedback from jsuarezruiz:

  • Suggested using width variable directly in conditions after variable assignment
  • Author (Ahamed-Ali) implemented this feedback

Review feedback from Copilot reviewer:

  • Noted test only verifies no crash, doesn't validate actual layout behavior
  • Suggested adding AutomationId to WebView for more comprehensive testing
  • Suggested adding toggle button to test visibility transitions

Low confidence comment (suppressed by Copilot):

  • Concern about incomplete logic when width or height is 0 and constraint is valid/finite
  • Suggested adding else clause to use constraint value when valid

Issue discussion highlights:

Reproduction Steps (From Issue)

  1. Add to MAUI template:
<ScrollView x:Name="myMediaFrame" IsVisible="False">
    <WebView x:Name="myWebView" HeightRequest="1000"/>
</ScrollView>
  1. Run on iOS
  2. Observe crash: CALayerInvalidGeometry: CALayer position contains NaN

Removing EITHER IsVisible="False" OR HeightRequest="1000" prevents crash.

Fix Candidates

# Source Approach Test Result Files Changed Notes
PR PR #29022 Handle infinite constraints in GetDesiredSize by using size.Width/size.Height instead of widthConstraint/heightConstraint directly ⏳ PENDING (Gate) WebViewHandler.iOS.cs (+4, -4) Original PR - prevents infinite values from propagating

Edge Cases to Verify

  • WebView layout when ScrollView visibility is toggled (suggested by Copilot)
  • WebView dimensions are correct when made visible
  • HeightRequest is respected after visibility toggle

🚦 Gate — Test Verification
📝 Review SessionOptimized the code · 493f5ec

Result: ✅ PASSED
Platform: ios
Mode: Full Verification

Verification Summary

Check Expected Actual Result
Tests WITHOUT fix FAIL FAIL
Tests WITH fix PASS PASS

Details

✅ Tests FAILED without fix (as expected)

  • Tests correctly detected the bug when the fix was not applied
  • Proves tests are effective at catching the issue

✅ Tests PASSED with fix (as expected)

  • Tests passed when the fix code was restored
  • Proves the fix actually resolves the issue

Conclusion

The verification confirms that:

  1. Tests properly reproduce the bug (fail without fix)
  2. Tests properly validate the fix (pass with fix)
  3. The fix is effective (resolves the issue the tests detect)

Fix Files Verified:

  • src/Core/src/Handlers/WebView/WebViewHandler.iOS.cs

🔧 Fix — Analysis & Comparison
📝 Review SessionOptimized the code · 493f5ec

Fix Candidates

# Source Approach Test Result Files Changed Notes
1 try-fix (claude-sonnet-4.5) Guard infinite constraints at ScrollView level ❌ FAIL ScrollView.cs (+22) Failed: Wrong abstraction layer - issue is in handler's value usage, not constraint propagation
2 try-fix (claude-opus-4.6) Sanitize final size against non-finite values with defensive guards ✅ PASS WebViewHandler.iOS.cs (+28, -8) More comprehensive than PR - adds explicit non-finite guards and per-dimension tracking
3 try-fix (gpt-5.2) Bound unbounded constraints using explicit Width/Height before base.GetDesiredSize ✅ PASS WebViewHandler.iOS.cs (+12) Preventive approach - bounds infinity constraints using HeightRequest/WidthRequest before measurement
4 try-fix (gpt-5.2-codex) Short-circuit ScrollView measure/arrange when invisible ✅ PASS ScrollView.cs (+16) Returns Size.Zero for invisible ScrollView, preventing infinite constraints from reaching children
5 try-fix (gemini-3-pro-preview) Initialize from size, only use constraint if finite and valid ✅ PASS WebViewHandler.iOS.cs (+10, -21) Simplification - initializes from size, only uses constraint when finite
PR PR #29022 Use size.Width/Height instead of widthConstraint/heightConstraint ✅ PASS (Gate) WebViewHandler.iOS.cs (+4, -4) Minimal targeted fix - uses measured size instead of raw constraints

Cross-Pollination Results

Round 2

Model Response
claude-sonnet-4.5 NEW IDEA: Cache and revalidate layout on visibility changes
claude-opus-4.6 NO NEW IDEAS
gpt-5.2 NEW IDEA: Cache and reuse last-known finite constraints
gpt-5.2-codex NEW IDEA: Clamp safe-area adjusted constraints
gemini-3-pro-preview NEW IDEA: Remove AdjustForFill call as no-op

Round 3 (Max rounds reached)

Model Response
claude-sonnet-4.5 NEW IDEA: Intercept NaN at CALayer level before position assignment
claude-opus-4.6 NO NEW IDEAS
gpt-5.2 NEW IDEA: Layout generation invalidation tied to iOS events
gpt-5.2-codex NO NEW IDEAS
gemini-3-pro-preview NEW IDEA: Skip measure when constraints match current size

Exhausted: No (max 3 rounds reached - 3 models still proposing ideas)

Note: Rounds 2-3 ideas were theoretical variations not empirically tested. Round 1 provided sufficient practical coverage with 4 passing alternatives.

Selected Fix

Selected Fix: PR's fix - Use size.Width/Height instead of widthConstraint/heightConstraint

Reasoning:

  1. Simplicity: The PR's fix is the most minimal change - only 4 lines modified (+4, -4). It directly addresses the root cause without adding defensive logic or changing behavior in other layers.

  2. Correctness: The fix correctly uses the measured size (size.Width/size.Height from base.GetDesiredSize()) instead of the raw constraint parameters. This is the intended behavior - handlers should respect their own measurement results.

  3. Targeted scope: The fix is applied exactly where the bug occurs (WebViewHandler.iOS.GetDesiredSize), rather than trying to prevent the symptom at a higher level (ScrollView) or adding defensive guards.

  4. Regression risk: Minimal - the change only affects WebView on iOS and follows the pattern established by the base class measurement logic.

  5. Alternatives analysis:

    • Attempt 2 (defensive guards): More complex (+28, -8 lines), adds redundant safety checks that shouldn't be needed if the root cause is fixed correctly
    • Attempt 3 (bound constraints): Adds logic before measurement, but doesn't address the actual bug (using constraint instead of size)
    • Attempt 4 (ScrollView short-circuit): Broader scope change, affects all ScrollView children, potential side effects
    • Attempt 5 (simplification): Better than attempt 2 but removes MinimumSize fallback that may be needed for truly zero-sized views

The PR's fix is the "Goldilocks" solution - not too defensive, not too preventive, just right. It fixes the actual bug (using constraint parameters instead of measured size) with minimal code change and clear intent.

Root Cause Analysis

Original Bug:

In WebViewHandler.iOS.cs, the GetDesiredSize method was initializing width and height from the raw constraint parameters (widthConstraint, heightConstraint) instead of from the measured size returned by base.GetDesiredSize().

// Original code (buggy)
var width = widthConstraint;  // Could be Infinity
var height = heightConstraint; // Could be Infinity

When a WebView with HeightRequest=1000 is placed inside a ScrollView with IsVisible=false:

  1. ScrollView passes infinite height constraint (scrollable container behavior)
  2. base.GetDesiredSize() measures the WebView and returns a valid finite size (e.g., height=1000)
  3. The original code initialized height = heightConstraint (Infinity)
  4. Since size.Height was non-zero, the if (size.Height == 0) guard was skipped
  5. The method returned new Size(width, height) with Infinity values
  6. iOS CALayer received NaN position values, causing CALayerInvalidGeometry crash

The Fix:

Initialize from the measured size instead of the constraint:

// Fixed code
var width = size.Width;  // Use measured size, not constraint
var height = size.Height; // Use measured size, not constraint

Now the return value uses the finite measured size (1000) instead of the infinite constraint (Infinity), preventing NaN propagation to CALayer.

Why Other Approaches Worked:

  • Attempt 2: Caught the Infinity values with explicit guards before returning
  • Attempt 3: Prevented Infinity from being passed to base.GetDesiredSize in the first place
  • Attempt 4: Prevented measurement entirely for invisible ScrollView
  • Attempt 5: Similar to PR but with different fallback logic

All passing approaches prevent Infinity from reaching the final return statement, but the PR's fix is the most direct and correct solution.


📋 Report — Final Recommendation
📝 Review SessionOptimized the code · 493f5ec

✅ Final Recommendation: APPROVE

Summary

PR #29022 correctly fixes an iOS crash where WebView with HeightRequest inside an invisible ScrollView causes a CALayerInvalidGeometry exception due to NaN position values. The fix is minimal, targeted, and properly tested.

Key strengths:

  • ✅ Surgical 4-line fix addressing the root cause
  • ✅ Comprehensive UI test coverage reproducing the exact bug scenario
  • ✅ Tested on all 4 platforms (iOS, Android, Windows, Mac)
  • ✅ Validated by Gate testing (tests FAIL without fix, PASS with fix)
  • ✅ Most optimal solution compared to 4 alternative approaches

Root Cause

The original code in WebViewHandler.iOS.GetDesiredSize initialized width and height from raw constraint parameters (widthConstraint, heightConstraint) instead of from the measured size returned by base.GetDesiredSize():

// Original (buggy)
var width = widthConstraint;  // Could be Infinity
var height = heightConstraint; // Could be Infinity

When a WebView with HeightRequest=1000 is inside a ScrollView with IsVisible=false:

  1. ScrollView passes infinite height constraint (scrollable container behavior)
  2. base.GetDesiredSize() measures and returns valid finite size (height=1000)
  3. Original code initialized height = heightConstraint (Infinity)
  4. Since size.Height was non-zero (1000), the if (size.Height == 0) guard was skipped
  5. Method returned new Size(width, height) with Infinity values
  6. iOS CALayer received NaN position values → CALayerInvalidGeometry crash

Fix Quality

The PR's fix is the optimal solution:

// Fixed
var width = size.Width;   // Use measured size
var height = size.Height; // Use measured size

Why this is the best approach:

  • Simplest: Only 4 lines changed (+4, -4) - most minimal change possible
  • Correct: Uses measured size from base.GetDesiredSize() as intended
  • Targeted: Applied exactly where the bug occurs
  • Low regression risk: Minimal scope change, iOS WebView only

Alternative approaches tested:

  • Attempt 2 (defensive guards): ✅ PASS but more complex (+28, -8 lines)
  • Attempt 3 (bound constraints): ✅ PASS but doesn't fix actual bug
  • Attempt 4 (ScrollView short-circuit): ✅ PASS but broader scope
  • Attempt 5 (simplification): ✅ PASS but removes safety fallback

The PR's fix is the "Goldilocks" solution - not over-engineered, not under-engineered, just right.

Test Coverage

Excellent test quality:

  • ✅ Reproduces exact bug scenario (WebView + HeightRequest + invisible ScrollView)
  • ✅ Clear test intent: "Test passes if no crash occurs"
  • ✅ Proper UI test with automation ID
  • ✅ Categorized correctly (UITestCategories.WebView)

Gate validation:

  • ✅ Tests FAIL without fix (correctly detects bug)
  • ✅ Tests PASS with fix (validates solution)

PR Description Quality

Current state: Good structure with clear explanation of root cause, description of change, and testing evidence.

Minor enhancements recommended (from pr-finalize):

  1. Add NOTE block at top for artifact testing (standard MAUI template)
  2. Enhance root cause section with more technical detail about the code path
  3. Optional: Document what PR Change iOS SetNeedsLayout propagation mechanism #26629 did differently for context

Platform Impact

Tested and verified:

  • ✅ iOS (primary affected platform)
  • ✅ Android (regression check)
  • ✅ Windows (regression check)
  • ✅ Mac (regression check)

Risk assessment:

  • Low risk: Change is iOS-specific and minimal
  • No observed regressions: All platforms tested successfully
  • Clear rollback path: Simply revert the 4-line change if issues arise

Regression Context

Important note: This issue was:

  1. Initially fixed by PR Simplify iOS ScrollView #26763 in version 9.0.30
  2. Regressed in version 9.0.50 due to changes in PR Change iOS SetNeedsLayout propagation mechanism #26629
  3. Now being fixed again by PR Fixed the crash on iOS when setting HeightRequest on WebView inside a ScrollView with IsVisible set to false #29022

The PR correctly identifies #26629 as the regressed PR. Future maintainers should be aware of this history when working on WebView layout code.

Verdict

APPROVE - This PR is ready to merge.

The fix is correct, well-tested, and represents the optimal solution among all alternatives. The regression context is documented, and the implementation follows best practices for minimal, targeted bug fixes.

Confidence: High - Gate validation, multi-platform testing, and exploration of 4 alternative approaches all confirm this is the right fix.


📋 Expand PR Finalization Review
Title: ✅ Good

Current: Fixed the crash on iOS when setting HeightRequest on WebView inside a ScrollView with IsVisible set to false

Description: ✅ Good
  1. Missing platform prefix [iOS] for platform-specific fix
  2. Too verbose - includes reproduction details rather than the fix itself
  3. Doesn't describe what the fix actually does
  4. Uses past tense "Fixed" instead of present tense imperative

✨ 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

When WebView is placed inside a ScrollView (especially with IsVisible=false), the measurement pass can receive infinite constraints. The previous implementation in GetDesiredSize used widthConstraint and heightConstraint directly to initialize the width and height variables. When these constraints were infinite, the code could propagate infinite or NaN values into subsequent calculations, causing crashes on iOS during layout operations.

The regression was introduced in PR #26629.

Description of Change

Changed WebViewHandler.iOS.cs to use the measured size (size.Width and size.Height from PlatformView.SizeThatFits) instead of the constraint values when initializing the width and height variables in GetDesiredSize.

Key change:

// Before (could use infinite constraints)
var width = widthConstraint;
var height = heightConstraint;

// After (use measured size, which is always finite)
var width = size.Width;
var height = size.Height;

The subsequent validation logic (checking if width/height is 0 and falling back to constraints if valid) remains the same, ensuring backward compatibility while preventing infinite values from being used in calculations.

What NOT to Do (for future agents)

  • Don't use constraint values directly without checking for infinity - Constraints can be infinite in scrollable containers (ScrollView, ListView). Always validate constraints before using them, or prefer using measured size from the native control.
  • Don't assume constraints are always finite in GetDesiredSize - Layout containers frequently pass infinite constraints during measurement to determine intrinsic size.

Regressed PR

Issues Fixed

Fixes #26795

Platforms Tested

  • Android
  • Windows
  • iOS
  • Mac

Screenshot

Before Issue Fix After Issue Fix
WebViewCrash.mov
WebViewFix.mov
Code Review: ✅ Passed

Code Review Findings for PR #29022

Summary

Overall Assessment: Code looks good

The fix is simple, focused, and correctly addresses the root cause of the crash. The change prevents infinite constraint values from being propagated in WebView measurement calculations on iOS.


Detailed Review

File: src/Core/src/Handlers/WebView/WebViewHandler.iOS.cs

Lines 72-75: Core fix

Correct approach

  • Changed from using widthConstraint/heightConstraint directly to using size.Width/size.Height
  • size comes from PlatformView.SizeThatFits(CGSize.Empty), which provides the WebView's intrinsic size
  • This prevents infinite or NaN values from being used in calculations

Lines 77, 87: Updated conditionals

Consistent logic

  • Conditionals now check the measured width/height variables instead of size.Width/size.Height
  • Maintains the same fallback behavior: if measured size is 0, fall back to constraints (if valid) or frame size

Impact:

  • ✅ Localized change - only affects iOS WebView measurement
  • ✅ No side effects on other platforms
  • ✅ Backward compatible for non-infinite constraint scenarios

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

Test scenario:

Good test case

  • Reproduces the exact crash scenario: WebView with HeightRequest inside invisible ScrollView
  • Simple and focused
  • Has AutomationId for verification

🟡 Minor suggestion (non-blocking):

Line 19: Uses external URL

Source = "https://en.m.wikipedia.org/wiki",

Recommendation: Consider using local HTML to eliminate external dependency:

Source = new HtmlWebViewSource { Html = "<html><body><h1>Test Content</h1></body></html>" }

Why: Makes test more reliable and faster (no network dependency). However, this is non-critical since the test is checking for crash on load, not content rendering.


File: src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue26795.cs

Appropriate test

  • Simple test that verifies no crash occurs
  • Uses WaitForElement("Label") to confirm app loaded successfully
  • Proper category (UITestCategories.WebView)
  • Follows established test patterns

Suggestions (Non-blocking)

1. Add Code Comment for Clarity

File: src/Core/src/Handlers/WebView/WebViewHandler.iOS.cs:72-75

Current:

var width = size.Width;
var height = size.Height;

Suggested addition:

// Use measured size instead of constraints to handle infinite values
// (e.g., when WebView is inside ScrollView with IsVisible=false)
var width = size.Width;
var height = size.Height;

Benefit: Makes the intent explicit for future maintainers who might wonder why we're not using constraints directly.


2. Consider Local HTML in Test

File: src/Controls/tests/TestCases.HostApp/Issues/Issue26795.cs:19

Reason: Eliminates network dependency, makes test faster and more reliable.

Implementation:

Source = new HtmlWebViewSource 
{ 
    Html = "<html><body><h1>Test Content</h1></body></html>" 
}

Positive Observations

  1. Simple, surgical fix - Changes only what's necessary to fix the bug
  2. Root cause addressed - Prevents infinite values at the source
  3. Well-tested - Includes UI test reproducing the crash scenario
  4. Cross-platform safety - iOS-specific file, no risk to Android/Windows
  5. Maintains backward compatibility - Fallback logic unchanged

Questions Answered

Q: Does this affect WebView behavior in other layout scenarios?

A: No. The change only affects the initial width/height variables used in the validation logic. The subsequent checks (lines 78-94) provide the same fallback behavior as before:

  • If measured size is 0 and constraint is valid → use constraint
  • If measured size is 0 and constraint is invalid → use frame size

Q: Why does this fix the crash?

A: When ScrollView has IsVisible=false, it passes infinite constraints during measurement. The old code would use these infinite values directly in calculations, potentially causing NaN or infinity to propagate through layout operations, triggering a crash. The new code uses the WebView's measured size (from SizeThatFits), which is always finite, preventing invalid values from entering calculations.

Q: What about the regression mentioned (PR #26629)?

A: PR #26629 likely introduced the direct use of constraints without proper validation. This PR correctly reverts to using measured size first, with constraints as a fallback only when needed.


Conclusion

Code Quality: ✅ Excellent

The implementation is clean, focused, and solves the problem correctly. The only suggestions are minor enhancements (code comment, test improvement) that would be nice-to-have but are not blockers for merge.

Merge Readiness: ✅ Ready (after title/description updates as noted in pr-finalize-summary.md)


@rmarinho rmarinho added s/agent-approved AI agent recommends approval - PR fix is correct and optimal s/agent-gate-passed AI verified tests catch the bug (fail without fix, pass with fix) s/agent-fix-lose 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) labels Feb 14, 2026
@kubaflo
Copy link
Contributor

kubaflo commented Feb 15, 2026

@Ahamed-Ali looks good! Could you review the AI Summary and let us know if you find it helpful?

@PureWeen PureWeen changed the base branch from main to inflight/current February 19, 2026 15:56
@PureWeen PureWeen merged commit c5d0dec into dotnet:inflight/current Feb 19, 2026
180 of 199 checks passed
@kubaflo kubaflo added s/agent-fix-pr-picked AI could not beat the PR fix - PR is the best among all candidates and removed s/agent-fix-lose AI could not beat the PR fix - PR is the best among all candidates labels Feb 20, 2026
github-actions bot pushed a commit that referenced this pull request Feb 21, 2026
… ScrollView with IsVisible set to false (#29022)

<!-- Please let the below note in for people that find this PR -->
> [!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](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!

### Root Cause

When WebView is placed inside a ScrollView (especially with
`IsVisible=false`), the measurement pass can receive infinite
constraints. The previous implementation in `GetDesiredSize` used
`widthConstraint` and `heightConstraint` directly to initialize the
`width` and `height` variables. When these constraints were infinite,
the code could propagate infinite or `NaN` values into subsequent
calculations, causing crashes on iOS during layout operations.

The regression was introduced in PR #26629.

### Description of Change

Changed `WebViewHandler.iOS.cs` to use the measured size (`size.Width`
and `size.Height` from `PlatformView.SizeThatFits`) instead of the
constraint values when initializing the `width` and `height` variables
in `GetDesiredSize`.

**Key change:**
```csharp
// Before (could use infinite constraints)
var width = widthConstraint;
var height = heightConstraint;

// After (use measured size, which is always finite)
var width = size.Width;
var height = size.Height;
```

The subsequent validation logic (checking if width/height is 0 and
falling back to constraints if valid) remains the same, ensuring
backward compatibility while preventing infinite values from being used
in calculations.

### What NOT to Do (for future agents)

- ❌ **Don't use constraint values directly without checking for
infinity** - Constraints can be infinite in scrollable containers
(ScrollView, ListView). Always validate constraints before using them,
or prefer using measured size from the native control.
- ❌ **Don't assume constraints are always finite in GetDesiredSize** -
Layout containers frequently pass infinite constraints during
measurement to determine intrinsic size.

### Regressed PR

- #26629

### Issues Fixed

Fixes #26795

### Platforms Tested

- [x] Android
- [x] Windows
- [x] iOS
- [x] Mac

### Screenshot

| Before Issue Fix | After Issue Fix |
|----------|----------|
| <video
src="https://github.com/user-attachments/assets/40f039b4-dc76-421f-9161-f4f98e23f621">
| <video
src="https://github.com/user-attachments/assets/632c0cf2-243d-489e-8bd2-baa0da7e05d5">
|
</details>

<details>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-controls-webview WebView 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-gate-passed AI verified tests catch the bug (fail without fix, pass with fix) s/agent-reviewed PR was reviewed by AI agent workflow (full 4-phase review)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Specifying HeightRequest in Webview when wrapped by ScrollView set "invisible" causes crash in iOS

5 participants