[Windows/Android] FlexLayout: Fix wrap misalignment due to floating-point precision - #31341
Conversation
|
/azp run MAUI-UITests-public |
|
Azure Pipelines successfully started running 1 pipeline(s). |
There was a problem hiding this comment.
Pull Request Overview
This PR fixes a FlexLayout wrapping issue specific to Windows where buttons with dynamic font changes don't wrap properly due to floating-point precision issues. The fix introduces a small tolerance value (0.1f) to the FlexLayout dimension calculation on Windows to ensure consistent wrapping behavior across platforms.
Key changes:
- Added platform-specific floating-point tolerance in FlexLayout wrapping logic
- Created comprehensive UI tests to validate the fix with dynamic button sizing
- Implemented test page with font family toggling to reproduce the original issue
Reviewed Changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
src/Core/src/Layouts/Flex.cs |
Adds Windows-specific tolerance to fix FlexLayout wrapping precision issues |
src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue30957.cs |
Implements NUnit UI test to verify FlexLayout wrapping behavior before/after font changes |
src/Controls/tests/TestCases.HostApp/Issues/Issue30957.cs |
Creates test page with FlexLayout and buttons that toggle font families to reproduce the issue |
| float flex_tolerance = layout.flex_dim; | ||
| #if WINDOWS | ||
| // Windows requires tolerance for floating-point precision issues in flex wrapping | ||
| flex_tolerance += 0.1f; |
There was a problem hiding this comment.
The magic number 0.1f lacks explanation for why this specific value was chosen. Consider defining this as a named constant with documentation explaining how this tolerance value was determined and whether it relates to specific Windows scaling factors or precision limits.
| float flex_tolerance = layout.flex_dim; | |
| #if WINDOWS | |
| // Windows requires tolerance for floating-point precision issues in flex wrapping | |
| flex_tolerance += 0.1f; | |
| flex_tolerance += WindowsFlexTolerance; |
|
|
||
| App.WaitForElement("Issue30957ToggleButton"); | ||
|
|
There was a problem hiding this comment.
There's an empty line after the WaitForElement call that serves no purpose and should be removed to improve code readability.
| App.WaitForElement("Issue30957ToggleButton"); |
|
I was able to reproduce this issue on Android. This fix only addresses Windows. |
| public void FlexLayoutWrappingWithToleranceWorksCorrectly() | ||
| { | ||
|
|
||
| App.WaitForElement("Issue30957ToggleButton"); |
There was a problem hiding this comment.
Seems can be still be reproduced on Android. #31341 (comment)
Could the test verify the rendering with snapshots?
There was a problem hiding this comment.
Hi @jsuarezruiz , The issue could not be reproduced on my end. Based on the reported issue on windows, it appears to be related to device density or another rendering factor.
Also, the test case has been updated to capture a screenshot for verification. Please review and confirm if any additional concerns remain.
There was a problem hiding this comment.
Yes, it does seem to be related to device density or other device display factor.
I tested with a pixel 5 emulator that has a density of 2.75, and the issue does not reproduce with the provided sample in the linked issue ( #30957 ). I then tested with a pixel 7, density 2.625, and it does reproduce the issue with the provided sample. 2.625 is a pretty common density among Android devices, and all of them with that density reproduce this issue with the sample.
I will note that almost every Android device I have tested will reproduce this issue, but in slightly different cases (different text in the buttons) depending on the device's density. I can confirm that the "Button1/Button2/Button3" text in the buttons used in the UI test doesn't reproduce on any of the Android device's I've tested. I don't know the details of what the UI tests are run on, but if there are details somewhere I can try to find a better repro for the automated test cases. Does the text in the #30957 sample also pass automated tests?
I also will note that because my team was experiencing this issue mostly on Android, we applied the workaround in the code here to our own branch of the FlexLayout and just removed the #if WINDOWS conditionals, and the issue seems to be mitigated on both platforms. I understand you probably can't merge code in without a valid A/B test case, but I do think this fix is best applied to all platforms, not just Windows. Again I am willing to help find better repro steps -- and I recommend testing with the emulator config below (and the text in the original issue) to validate the linked issue repros on Android.
config.ini
disk.dataPartition.size=6442450944
fastboot.forceColdBoot=no
fastboot.forceFastBoot=yes
hw.accelerometer=yes
hw.arc=no
hw.audioInput=yes
hw.battery=yes
hw.camera.back=virtualscene
hw.camera.front=emulated
hw.cpu.ncore=4
hw.dPad=no
hw.gps=yes
hw.gpu.mode=auto
hw.keyboard=yes
hw.lcd.density=420
hw.lcd.height=1200
hw.lcd.width=540
hw.mainKeys=no
hw.ramSize=1536
hw.sdCard=yes
hw.sensors.orientation=yes
hw.sensors.proximity=yes
hw.trackBall=no
sdcard.size=512M
skin.dynamic=yes
skin.name=1080x2400
vm.heapSize=256
hw.device.hash2=MD5:9cfa1e95ac9cd7b57d7aac913d0b34ca17a9d277d6036111b5bd65a8291598a3
hw.device.name=pixel_7
hw.device.manufacturer=Google
showDeviceFrame=no
tag.id=google_apis_playstore
tag.display=Google Play
PlayStore.enabled=true
abi.type=x86_64
hw.cpu.arch=x86_64
hw.gpu.enabled=yes
avd.ini.displayname=Pixel 7 - API 36
image.sysdir.1=system-images\android-36\google_apis_playstore\x86_64\
AvdId=pixel_7_-_api_36
🤖 AI Summary📊 Expand Full Review🔍 Pre-Flight — Context & Validation📝 Review Session — Update Flex.cs ·
|
| File:Line | Reviewer Says | Author Says | Status |
|---|---|---|---|
| Flex.cs:539 | Magic number 0.1f lacks explanation | Named constant + XML doc added | Addressed |
| Issue30957.cs:20 (jsuarezruiz) | Test should verify rendering with snapshots | Updated test to use VerifyScreenshot | Addressed |
| Issue30957.cs:20 (DavidIDCI) | "Button1/Button2/Button3" text doesn't reproduce issue on any tested Android device; need repro that actually triggers precision issue | No response | |
| Issue30957.cs:21 (Copilot) | Empty line after WaitForElement should be removed | Not addressed | Minor - unresolved |
| Flex.cs comment | "Hence, minimum tolerance for floating-point precision issues in flex wrapping" runs on awkwardly; missing space | Not addressed | Minor - unresolved |
Fix Candidates
| # | Source | Approach | Test Result | Files Changed | Notes |
|---|---|---|---|---|---|
| PR | PR #31341 | Add FlexWrapTolerance = 0.1f to flex_dim comparison (unconditional, all platforms) |
⏳ PENDING (Gate) | Flex.cs (+18/-1) |
Applied unconditionally; tolerance value 0.1f basis not fully documented |
🚦 Gate — Test Verification
📝 Review Session — Update Flex.cs · 52ffd1d
Result: ❌ FAILED
Platform: ios
Mode: Full Verification
- Tests WITHOUT fix: ✅ PASS (unexpected — should FAIL to catch the bug)
- Tests WITH fix: ✅ PASS (expected)
Verification Output
╔═══════════════════════════════════════════════════════════╗
║ VERIFICATION FAILED ❌ ║
╠═══════════════════════════════════════════════════════════╣
║ Tests PASSED without fix (should fail) ║
║ - Tests don't actually detect the bug ║
╚═══════════════════════════════════════════════════════════╝
Root Cause of Gate Failure
The test in Issue30957.cs uses buttons with text "Button1", "Button2", "Button3". This specific button text does NOT trigger the floating-point precision issue on iOS (or Android, as confirmed by reviewer @DavidIDCI). The precision issue is sensitive to button text length, font metrics, and device DPI density.
The test verifies that three buttons exist in a FlexLayout, toggles their font family, and takes a screenshot — but because the button widths with this text don't land near the FlexLayout boundary where floating-point errors manifest, the test always passes regardless of whether the tolerance fix is present.
Fix File Identified
src/Core/src/Layouts/Flex.cs(theFlexWrapTolerance = 0.1ffix)
🔧 Fix — Analysis & Comparison
📝 Review Session — Update Flex.cs · 52ffd1d
Fix Candidates
| # | Source | Approach | Test Result | Files Changed | Notes |
|---|---|---|---|---|---|
| PR | PR #31341 | Add FlexWrapTolerance = 0.1f to flex_dim comparison |
✅ PASS with fix (test not reliable) | Flex.cs (+18/-1) |
Gate FAILED - test passes without fix too |
Exhausted: N/A (Gate failed — Fix phase skipped per workflow)
Selected Fix: PR's fix — Gate failed so no try-fix was run; the PR fix code change is technically sound but tests don't validate it
Gate FAILED reason: Tests pass both with and without the fix because the "Button1/Button2/Button3" button text does not trigger the precision issue on tested devices.
📋 Report — Final Recommendation
📝 Review Session — Update Flex.cs · 52ffd1d
⚠️ Final Recommendation: REQUEST CHANGES
Summary
PR #31341 addresses a genuine bug: floating-point precision errors in FlexLayout's wrap algorithm cause items to wrap prematurely when DPI scaling causes flex_dim to be calculated slightly smaller than the actual child size. The fix — adding FlexWrapTolerance = 0.1f to the comparison — is technically sound and applied unconditionally across all platforms.
However, Gate FAILED on both iOS (this review) and Android (prior review): the UI test does not actually catch the bug. The test uses buttons with short text ("Button1", "Button2", "Button3"), which does not trigger the floating-point precision issue on the test devices. The test passes both with and without the fix, making it unable to serve as a regression guard.
Root Cause
Flex.cs wrap decision logic in layout_item():
// Before (buggy):
if (layout.flex_dim < child_size) // flex_dim can be slightly smaller due to DPI scaling
// After (fixed):
float flex_tolerance = layout.flex_dim + FlexWrapTolerance;
if (flex_tolerance < child_size)DPI scaling causes sub-pixel rounding differences between flex_dim and child_size. When flex_dim is calculated slightly smaller than the actual child size, items are incorrectly wrapped to a new line despite sufficient space. The 0.1f tolerance absorbs this rounding error.
Gate Status: ❌ FAILED
Verified on iOS (this review) and previously on Android (prior review):
- Tests PASS without fix (unexpected — tests don't catch the bug)
- Tests PASS with fix (expected)
The test button text "Button1/Button2/Button3" does not reproduce the floating-point precision issue on tested iOS/Android devices. Reviewer @DavidIDCI confirmed this on Android: the issue reproduces on Pixel 7 (density 2.625) but not with this specific button text on tested devices.
Issues Found
🔴 Critical: Test does not catch the bug (Gate FAILED)
- Files:
src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue30957.cs,src/Controls/tests/TestCases.HostApp/Issues/Issue30957.cs - Problem: Button text "Button1/Button2/Button3" does not trigger the sub-pixel rounding discrepancy on tested devices. Confirmed FAILED on both Android (prior agent review) and iOS (this review).
- Fix needed: The test must use button text or layout dimensions that actually land near the FlexLayout boundary where floating-point errors manifest. Options:
- Use longer button text that makes buttons wider, closer to the wrapping boundary
- Set the
FlexLayoutto a fixed narrow width that creates a boundary condition for the precision issue - Add a unit test in
Controls.Core.UnitTeststhat directly testsFlex.cslayout logic with crafted float values exposing the rounding error (more reliable, not device-density-dependent) - Find the exact text from the original issue sample that @DavidIDCI confirmed reproduces on Android density 2.625 devices
🟡 Minor: Malformed inline comment in Flex.cs
- File:
src/Core/src/Layouts/Flex.cs(line ~550) - Problem: Comment reads:
"...behavior.Hence, minimum tolerance for..."— missing space before "Hence" and sentence structure is broken - Fix:
"...behavior. Hence, a minimum tolerance is applied for floating-point precision issues in flex wrapping."
🟡 Minor: Empty line in test method
- File:
src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue30957.cs:19 - Problem: Blank line after opening brace of test method before
WaitForElementcall - Fix: Remove the blank line
🟡 Minor: No newline at end of file
- Files:
Issue30957.cs(both HostApp and Shared.Tests) - Problem: Files end without trailing newline
- Fix: Add trailing newline
Fix Quality Assessment (Code Itself)
The fix itself is well-structured:
- ✅
FlexWrapTolerance = 0.1fnamed constant (not a raw magic number) - ✅ Well-documented with XML doc comments
- ✅ Applied unconditionally across all platforms (correct, since Android is also affected)
⚠️ The value0.1flacks a documented basis for why this specific value was chosen over alternatives like0.01for0.5f. The comment should mention that0.1frepresents approximately the maximum sub-pixel rounding error expected from common DPI scaling factors.
Title Assessment
Current: [Windows/Android] FlexLayout: Fix wrap misalignment due to floating-point precision
Assessment: The title says [Windows/Android] but the fix is applied unconditionally to all platforms. Consider removing the platform prefix or changing it to reflect all platforms.
Recommended: FlexLayout: Fix wrap misalignment due to floating-point precision (all platforms)
Description Assessment
The PR description is adequate — it has the NOTE block, root cause, description of change, and issue links. The description of "scaling" correctly identifies the root cause.
📋 Expand PR Finalization Review
Title: ⚠️ Needs Update
Current: [Windows/Android] FlexLayout: Fix wrap misalignment due to floating-point precision
Recommended: FlexLayout: Fix wrap misalignment due to floating-point precision (Windows/Android primary)
Description: ⚠️ Needs Update
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
FlexLayout wrap detection uses a floating-point comparison to decide whether a child item fits on the current line: flex_dim < child_size. On Windows (especially at non-integer DPI scaling factors like 1.25x) and on Android (at densities like 2.625x on Pixel 7), the available flex dimension can be computed fractionally smaller than the child's measured size due to rounding during DPI/density conversion. This causes children that should fit on the current line to be incorrectly moved to a new line.
The bug manifests most visibly when buttons dynamically change their FontFamily at runtime, which triggers re-measurement with slightly different sizes.
Description of Change
Introduced a small floating-point tolerance constant (FlexWrapTolerance = 0.1f) in src/Core/src/Layouts/Flex.cs. The wrap line detection check is updated from:
if (layout.flex_dim < child_size)
to:
float flex_tolerance = layout.flex_dim + FlexWrapTolerance;
if (flex_tolerance < child_size)
This tolerance is applied unconditionally across all platforms. Since the value (0.1f) is well below any intentional layout gap (always ≥ 1 device-independent unit), it has no adverse effect on correct wrapping behavior on any platform.
Key Technical Details
- Affected file:
src/Core/src/Layouts/Flex.cs— the shared cross-platform flex layout engine - Constant:
FlexWrapTolerance = 0.1f— accounts for sub-pixel rounding from DPI/density scaling - Platforms affected: Windows (DPI scaling, e.g., 1.25x) and Android (density, e.g., 2.625 on Pixel 7). iOS/Mac may benefit as a safe cross-platform fix.
Issues Fixed
Fixes #30957
Platforms Tested
- Android
- Windows
- iOS
- Mac
Code Review: ✅ Passed
Code Review Findings — PR #31341
🟡 Suggestions
1. Tolerance Value Choice Is Not Documented
File: src/Core/src/Layouts/Flex.cs
Location: private const float FlexWrapTolerance = 0.1f;
Problem: The constant 0.1f is arbitrary and its origin is unexplained. The XML doc comment says "A small tolerance value" but doesn't justify why 0.1f specifically (vs 0.01f, 0.5f, 1.0f). The original Copilot reviewer flagged this as well. The constant name FlexWrapTolerance is good, but the value selection needs rationale.
Recommendation: Add a comment near the constant explaining the rationale — e.g., "0.1f represents sub-pixel precision threshold; typical DPI scaling factors on Windows (e.g., 1.25x, 1.5x) can introduce rounding errors up to ~0.1 device-independent units."
// 0.1f accounts for sub-pixel rounding errors introduced by DPI scaling factors
// (e.g., 1.25x on Windows, 2.625x density on Android). Values below 1.0f have
// no meaningful effect on intentional layout gaps which are always >= 1dp.
private const float FlexWrapTolerance = 0.1f;2. Malformed Code Comment in layout_item
File: src/Core/src/Layouts/Flex.cs
Location: Lines 546–551 (the multi-line comment before flex_tolerance)
Problem: The comment ends with a sentence fragment: "Hence, minimum tolerance for floating-point precision issues in flex wrapping". This is grammatically incomplete and was apparently appended accidentally.
Current:
// The issue was originally reported on Windows and related to device
// density or scaling factor. In a few scenarios, the same issue has also
// been reproduced on Android due to device density variations. The tolerance value
// is applied unconditionally across all platforms as a safer fix, since it has no
// adverse effects on layout behavior.Hence, minimum tolerance for floating-point precision issues in flex wrapping
float flex_tolerance = layout.flex_dim + FlexWrapTolerance;Recommended:
// The issue was originally reported on Windows, related to device density or
// scaling factor. It has also been reproduced on Android due to density variations.
// The tolerance is applied unconditionally across all platforms as a conservative fix;
// it has no adverse effects on layout behavior.
float flex_tolerance = layout.flex_dim + FlexWrapTolerance;3. Unnecessary Empty Line in UI Test
File: src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue30957.cs
Location: After App.WaitForElement("Issue30957ToggleButton");
Problem: There is a blank line between WaitForElement and Tap that serves no purpose (also flagged by Copilot reviewer).
Current:
App.WaitForElement("Issue30957ToggleButton");
App.Tap("Issue30957ToggleButton");(with blank line between them in the actual code)
Recommended: Remove the blank line.
4. UI Test Does Not Verify Wrap Behavior
File: src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue30957.cs
Problem: The test taps the toggle button, waits for the 3 buttons to exist, and takes a screenshot. However, it does not verify that the buttons are actually on one line (not wrapped). WaitForElement just checks existence, not position. The screenshot test relies entirely on visual comparison — if no baseline exists for the Android emulator used in CI, the test may be silently passing without actually checking the layout.
Additionally: The reviewer comment from DavidIDCI (October 2025) indicates the specific text "Button1/Button2/Button3" does NOT reproduce the issue on many Android devices — the test may be testing a scenario that doesn't actually trigger the bug.
Recommendation: Consider adding element position/rect assertions to verify buttons are on a single row:
var rect1 = App.WaitForElement("Issue30957Button1").GetRect();
var rect2 = App.WaitForElement("Issue30957Button2").GetRect();
// Buttons should be on same row (same Y coordinate within tolerance)
Assert.That(Math.Abs(rect1.Y - rect2.Y), Is.LessThan(5), "Buttons should be on the same line");5. Missing Newline at End of Files
Files:
src/Controls/tests/TestCases.HostApp/Issues/Issue30957.cssrc/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue30957.cs
Both files are missing a newline at end of file (indicated by \ No newline at end of file in the diff). This is a minor formatting issue but inconsistent with repository conventions.
✅ Looks Good
- Constant is properly named (
FlexWrapTolerance) — descriptive and searchable - XML doc comment on the constant is helpful for future readers
- Fix logic is correct — comparing
layout.flex_dim + FlexWrapTolerance < child_sizeis the right predicate - Cross-platform application of the fix is the right call (the fix is in shared
Flex.cs, no#ifguards needed) - UI test structure follows repository conventions (
_IssuesUITest,[Category(UITestCategories.Layout)],AutomationIds on elements) - HostApp page follows
[Issue]attribute conventions and uses C# (not XAML), per guidelines - Snapshot images added for Android and iOS
🤖 AI Summary📊 Expand Full Review —
|
| File | Reviewer | Comment | Status |
|---|---|---|---|
Flex.cs:539 |
copilot-pr-reviewer | Magic number 0.1f needs explanation | Addressed (constant named + commented) |
Issue30957.cs |
jsuarezruiz | Should verify rendering with snapshots | Partially addressed — author says screenshot added |
Issue30957.cs |
jsuarezruiz | Bug still reproducible on Android | Author disputes; @DavidIDCI confirms Android repro |
Issue30957.cs |
DavidIDCI | Button text doesn't repro on test devices; fix should be all platforms | Open / unresolved |
Files Changed
Fix files (1):
src/Core/src/Layouts/Flex.cs(+20/-1): AddsFlexWrapTolerance = 0.1fin#if ANDROID || WINDOWSblock, changes wrap check fromlayout.flex_dim < child_sizetoflex_tolerance < child_size
Test files (2):
src/Controls/tests/TestCases.HostApp/Issues/Issue30957.cs(+126): Test page with 3 buttons in FlexLayout, toggle button to switch font familysrc/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue30957.cs(+35): NUnit UI test asserting same Y position and ordered X positions after font toggle
Fix Candidates
| # | Source | Approach | Test Result | Files Changed | Notes |
|---|---|---|---|---|---|
| PR | PR #31341 | Add FlexWrapTolerance = 0.1f in #if ANDROID || WINDOWS block |
❌ Gate FAILED (test doesn't catch bug) | Flex.cs |
Original PR fix |
🔧 Fix — Analysis & Comparison
Fix Candidates
| # | Source | Approach | Test Result | Files Changed | Notes |
|---|---|---|---|---|---|
| 1 | try-fix (claude-opus-4.6) | Unconditional 0.1f tolerance (remove #if ANDROID || WINDOWS) + improved test with explicit-sized labels |
✅ PASS | Flex.cs, Issue30957.cs (both) |
Simpler than PR; unconditional; test improved |
| 2 | try-fix (claude-sonnet-4.6) | Round both flex_dim and child_size to 3 decimal places (MathF.Round) before comparison — symmetric noise elimination, no platform guards |
✅ PASS | Flex.cs |
Symmetric vs PR's one-sided bias; no magic constant |
| 3 | try-fix (gpt-5.3-codex) | Scale-aware relative epsilon: NeedsWrap(flex_dim, child_size) helper using `max( |
a | , | b |
| 4 | try-fix (gemini-3-pro-preview) | ⏳ IN PROGRESS | — | — | — |
| PR | PR #31341 | Add FlexWrapTolerance = 0.1f in #if ANDROID || WINDOWS block |
❌ Gate FAILED (test doesn't catch bug) | Flex.cs |
Platform-conditional only |
Cross-Pollination
| Model | Round | New Ideas? | Details |
|---|---|---|---|
| — | 2 | ⏳ PENDING | — |
Exhausted: No (2 of 4 models remaining)
Selected Fix: TBD
🤖 AI Summary📊 Expand Full Review —
|
| File:Line | Reviewer | Issue | Status |
|---|---|---|---|
Flex.cs:539 |
Copilot | Magic number 0.1f explanation | Addressed (named const + XML docs added) |
Issue30957.cs:20 |
jsuarezruiz | Test should use snapshots | Addressed (VerifyScreenshot removed, Y/X position checks used instead) |
Issue30957.cs:20 |
DavidIDCI | "Button1/Button2/Button3" text doesn't reproduce on any Android device tested | |
Issue30957.cs:21 |
Copilot | Empty line after WaitForElement |
Files Changed
Fix files (1):
src/Core/src/Layouts/Flex.cs(+20/-1): AddsFlexWrapTolerance = 0.1fconstant under#if ANDROID || WINDOWS, applies it to wrap boundary comparison
Test files (2):
src/Controls/tests/TestCases.HostApp/Issues/Issue30957.cs(new, +126): Test page with FlexLayout, font-family toggle triggersrc/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue30957.cs(new, +35): NUnit UI test checking button Y-positions match after toggle
Test Type: UI Tests (position assertions, no screenshot verification)
Fix Candidates
| # | Source | Approach | Test Result | Files Changed | Notes |
|---|---|---|---|---|---|
| PR | PR #31341 | Add FlexWrapTolerance = 0.1f under #if ANDROID || WINDOWS, add to flex_dim comparison |
❌ Gate FAILED (test doesn't catch bug) | Flex.cs (+20/-1) |
Fix code is correct; test is inadequate; iOS/Mac not covered |
🔧 Fix — Analysis & Comparison
Fix Candidates
| # | Source | Approach | Test Result | Files Changed | Notes |
|---|---|---|---|---|---|
| 1 | try-fix (opus) | Unconditional 0.1f tolerance (no #if) + FixedMeasureBox 300dp/100.07dp test |
✅ PASS | Flex.cs (+8/-1), HostApp (+69/-122), Shared (+38/-32) |
Removes platform conditional; test reliable but needs custom ContentView |
| 2 | try-fix (sonnet) | Unit test Core.UnitTests + relative tolerance child_size * 0.001f (no #if) |
✅ PASS | Flex.cs (+4/-1), new unit test (+62) |
Device-free; deterministic; simplest fix overall |
| 3 | try-fix (codex) | ULP-based ShouldWrap() + FlexBasis(1/3 relative) 100dp test |
✅ PASS | Flex.cs (+ULP method), HostApp (FlexBasis) |
Works but ULP comparison in layout engine is overcomplicated |
| 4 | try-fix (gpt-5.4) | Round remaining-space to 4 decimals + "MMMMMMMM" text | ❌ FAIL | Flex.cs, HostApp |
Test still passed without fix |
| 5 | try-fix (sonnet cross-poll R1) | Pixel-snap child sizes in FlexLayout.cs via DeviceDisplay.MainDisplayInfo.Density |
✅ PASS | FlexLayout.cs (+21) |
Fixes root cause at boundary; but couples to DeviceDisplay + try/catch smell |
| 6 | try-fix (sonnet cross-poll R2) | Recompute flex_dim = size_dim - occupied_dim (single subtraction) |
❌ FAIL | Flex.cs (+6/-4) |
Mathematically equivalent; root cause is dp/pixel mismatch not accumulation |
| PR | PR #31341 | FlexWrapTolerance = 0.1f under #if ANDROID || WINDOWS |
❌ Gate FAILED | Flex.cs (+20/-1) |
Test doesn't catch bug; #if unnecessarily excludes iOS/Mac |
Cross-Pollination
| Model | Round | New Ideas? | Details |
|---|---|---|---|
| claude-opus-4.6 | 2 | Yes | Integer pixel comparison in wrap check (covered by Attempt 5 approach) |
| claude-sonnet-4.6 | 2 | Yes → Attempt 6 | Recompute fresh — FAILED (equivalent math) |
| gpt-5.3-codex | 2 | Yes | Kahan/double summation — equivalent failure mode to Attempt 6 |
| claude-opus-4.6 | 3 | NO NEW IDEAS | Root cause fully explored; only tolerance or pixel-snapping viable |
Exhausted: Yes — problem space covered; all fix strategies (tolerance vs pixel-snapping) attempted
Selected Fix: Attempt 2 (sonnet) — unit test + child_size * 0.001f relative tolerance (no #if)
Rationale: Attempt 2 is the best overall:
- Simplest Flex.cs change (4 lines, no platform
#if, no new struct fields) - Best test (device-free unit test, deterministic, ~66ms)
- Clean relative tolerance scales correctly for any child size
- No custom ContentView, no DeviceDisplay coupling, no ULP complexity
Compared to PR's fix: same strategy (tolerance) but universal (no #if ANDROID || WINDOWS) and with a test that actually catches the bug.
📋 Report — Final Recommendation
⚠️ Final Recommendation: REQUEST CHANGES
Phase Status
| Phase | Status | Notes |
|---|---|---|
| Pre-Flight | ✅ COMPLETE | Issue #30957, FlexLayout float precision wrap bug |
| Gate | ❌ FAILED | Android — tests pass both with and without fix |
| Try-Fix | ✅ COMPLETE | 6 attempts: 4 passing, 2 failing; Attempt 2 selected as best |
| Report | ✅ COMPLETE |
Summary
PR #31341 addresses a genuine and confirmed bug in FlexLayout's wrap algorithm: floating-point precision from DPI density causes flex_dim to be computed slightly smaller than child_size, triggering premature wrapping. The fix strategy (adding a small tolerance to the wrap comparison) is correct. However, Gate FAILED on Android: the tests added by this PR pass identically with and without the fix, providing zero regression protection.
Try-Fix exploration found a better alternative (Attempt 2) that:
- Removes the unnecessary
#if ANDROID || WINDOWSconditional — makes the fix universal - Adds a properly-behaved relative tolerance (
child_size * 0.001f) rather than a magic absolute constant - Includes a device-free unit test in
Core.UnitTeststhat deterministically catches the bug in ~66ms
Root Cause
Flex.cs layout_items() uses layout.flex_dim < child_size to decide if a child wraps. DPI density scaling creates an asymmetry:
- Container width (from platform): 300dp → 788px → 300.19dp (pixel-rounded)
- Child widths (from
MeasureOverride): exact dp values, e.g., 100.07dp - After 2 children:
flex_dim = 300.19 - 100.07 - 100.07 = 100.05dp 100.05 < 100.07→ 3rd child wraps despite fitting
The fix must absorb the ~0.02dp discrepancy. Approach verified empirically: flex_dim + child_size * 0.001f < child_size (i.e., remaining space must be less than 99.9% of child size to wrap).
Gate Status: ❌ FAILED
Verified on Android (this review):
- Tests PASS without fix — tests do not catch the bug
- Tests PASS with fix — expected
Root cause: button text "Button1/Button2/Button3" does not create a dimension near the FlexLayout wrap boundary on the test device. Confirmed by reviewer @DavidIDCI: issue density-sensitive, reproduces on Pixel 7 (2.625) but not with this text.
Issues Found
🔴 Critical: Tests don't catch the bug (Gate FAILED)
- Problem:
Issue30957.cs(HostApp) uses short button text that doesn't trigger the precision issue on test devices. Confirmed failing on Android (this review) and iOS (prior review). - Better approach found: Unit test in
Core.UnitTestsusingMeasureOverrideto inject exact float values (300.19fcontainer,100.07fchildren) — deterministic, device-free, reliably fails without fix and passes with fix. - Suggested fix (from Attempt 2):
// In src/Controls/tests/Core.UnitTests/Layouts/Issue30957.cs (new file): // Uses CrossPlatformMeasure(300.19f, 200) + CrossPlatformArrange() // to directly exercise the Flex.cs wrap check with exact precision-triggering values
🔴 Critical: #if ANDROID || WINDOWS unnecessarily restricts the fix
- Problem: iOS and macCatalyst can also experience float precision issues at non-integer densities, yet the fix is excluded via
#if ANDROID || WINDOWS. The PR description says "applied unconditionally" but the code contradicts this. - Better approach (from Attempt 2): Remove the conditional entirely. The tolerance
child_size * 0.001f(0.1% of child size) is safe on all platforms — it only prevents wrapping when remaining space is within 0.1% of child size, which is always a rounding artifact, never intentional.
🟡 Minor: PR description vs implementation mismatch
- PR description says "This tolerance is applied unconditionally across all platforms" but
Flex.csuses#if ANDROID || WINDOWS. Should be corrected.
🟡 Minor: Empty line in test method
src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue30957.cs:21— blank line afterWaitForElementcall. Remove.
🟡 Minor: Malformed comment in Flex.cs
- Line ~549:
"...behavior.Hence, minimum tolerance..."— missing space before "Hence".
Fix Quality Assessment
The code fix in Flex.cs is technically sound — adding tolerance to the wrap comparison is the correct approach for floating-point geometry. The named constant and XML documentation are good. However:
| Aspect | PR's Fix | Attempt 2 (Better) |
|---|---|---|
| Platform coverage | #if ANDROID || WINDOWS only |
Universal (all platforms) |
| Tolerance type | Absolute 0.1f |
Relative child_size * 0.001f |
| Test reliability | ❌ Doesn't catch bug | ✅ Deterministic unit test |
| Test speed | Minutes (device required) | ~66ms (no device needed) |
| Lines changed (fix) | +20/-1 | +4/-1 |
Suggested Changes for PR Author
-
Replace the
#if ANDROID || WINDOWSblock with unconditional tolerance:// Replace platform conditional with universal tolerance if (layout.flex_dim + child.Frame[layout.frame_size_i] * 0.001f < child.Frame[layout.frame_size_i])
Or keep named constant for readability:
const float wrapTolerance = child_size * 0.001f; if (layout.flex_dim + wrapTolerance < child_size)
-
Replace the UI test with a unit test in
src/Controls/tests/Core.UnitTests/Layouts/Issue30957.csthat:- Uses
CrossPlatformMeasure(300.19f, 200)+CrossPlatformArrange()on a FlexLayout - Injects exact
100.07fvalues viaMeasureOverridein a custom FixedSizeLabel - Asserts
child.Frame.Y == 0for all 3 children (all on row 0) - Runs in ~66ms with no device dependency
- Uses
-
Update PR title to remove
[Windows/Android]prefix since fix is universal:FlexLayout: Fix wrap misalignment due to floating-point precision rounding
kubaflo
left a comment
There was a problem hiding this comment.
The test couldn't catch a bug - can you please verify?
|
@kubaflo , While working on this issue,I have observed that it does not reproduce locally when display scaling is set to 100%. The behavior occurs only when scaling is increased to 125% or higher, which cannot be replicated in CI environments. As a result, the Gate failure was environment‑specific and not indicative of a regression under normal scaling. To ensure coverage, a UITest has been added and validated manually for high display‑scaling scenarios. |
|
@SuthiYuvaraj okay, thanks for letting me know :) |
|
/review -b feature/refactor-copilot-yml |
MauiBot
left a comment
There was a problem hiding this comment.
Expert Review — 1 findings
See inline comments for details.
| [Category(UITestCategories.Layout)] | ||
| public void FlexLayoutWrappingWithToleranceWorksCorrectly() | ||
| { | ||
| App.WaitForElement("Issue30957ToggleButton"); |
There was a problem hiding this comment.
[moderate] Regression Prevention — This test taps the toggle and then immediately measures elements that already existed and already satisfied these assertions before the tap. If the click handler does not run, or if the font-family change has not completed layout yet, the test can still pass by measuring the initial layout. Please wait/assert an observable post-toggle state, such as the status label changing to the semibold state, before reading the button rects.
…oint precision (#31341) <!-- 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 FlexLayout wrap detection uses a floating-point comparison to decide whether a child item fits on the current line: flex_dim < child_size. On Windows (especially at non-integer DPI scaling factors like 1.25x) and on Android (at densities like 2.625x on Pixel 7), the available flex dimension can be computed fractionally smaller than the child's measured size due to rounding during DPI/density conversion. This causes children that should fit on the current line to be incorrectly moved to a new line. The bug manifests most visibly when buttons dynamically change their FontFamily at runtime, which triggers re-measurement with slightly different sizes. ### Description of Change Introduced a small floating-point tolerance constant (FlexWrapTolerance = 0.1f) in src/Core/src/Layouts/Flex.cs. The wrap line detection check is updated from: `if (layout.flex_dim < child_size)` to: ``` float flex_tolerance = layout.flex_dim + FlexWrapTolerance; if (flex_tolerance < child_size) ``` This tolerance is applied unconditionally across all platforms. Since the value (0.1f) is well below any intentional layout gap (always ≥ 1 device-independent unit), it has no adverse effect on correct wrapping behavior on any platform. ### Key Technical Details **Affected file:** src/Core/src/Layouts/Flex.cs — the shared cross-platform flex layout engine **Constant:** FlexWrapTolerance = 0.1f — accounts for sub-pixel rounding from DPI/density scaling **Platforms affected:** Windows (DPI scaling, e.g., 1.25x) and Android (density, e.g., 2.625 on Pixel 7). iOS/Mac may benefit as a safe cross-platform fix. ### Issues Fixed Fixes #30957 ### Tested the behaviour in the following platforms - [x] Android - [x] Windows - [ ] iOS - [ ] Mac ### Output Screenshot Before Issue Fix | After Issue Fix | |----------|----------| |<image width="300" height="150" alt="Before Fix" src="https://github.com/user-attachments/assets/ff89beda-1093-46fc-9aa6-4df3372f937f">|<image width="300" height="150" alt="After Fix" src ="https://github.com/user-attachments/assets/e3544ed0-7004-4239-8fd8-458e13b88281">|
…oint precision (#31341) <!-- 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 FlexLayout wrap detection uses a floating-point comparison to decide whether a child item fits on the current line: flex_dim < child_size. On Windows (especially at non-integer DPI scaling factors like 1.25x) and on Android (at densities like 2.625x on Pixel 7), the available flex dimension can be computed fractionally smaller than the child's measured size due to rounding during DPI/density conversion. This causes children that should fit on the current line to be incorrectly moved to a new line. The bug manifests most visibly when buttons dynamically change their FontFamily at runtime, which triggers re-measurement with slightly different sizes. ### Description of Change Introduced a small floating-point tolerance constant (FlexWrapTolerance = 0.1f) in src/Core/src/Layouts/Flex.cs. The wrap line detection check is updated from: `if (layout.flex_dim < child_size)` to: ``` float flex_tolerance = layout.flex_dim + FlexWrapTolerance; if (flex_tolerance < child_size) ``` This tolerance is applied unconditionally across all platforms. Since the value (0.1f) is well below any intentional layout gap (always ≥ 1 device-independent unit), it has no adverse effect on correct wrapping behavior on any platform. ### Key Technical Details **Affected file:** src/Core/src/Layouts/Flex.cs — the shared cross-platform flex layout engine **Constant:** FlexWrapTolerance = 0.1f — accounts for sub-pixel rounding from DPI/density scaling **Platforms affected:** Windows (DPI scaling, e.g., 1.25x) and Android (density, e.g., 2.625 on Pixel 7). iOS/Mac may benefit as a safe cross-platform fix. ### Issues Fixed Fixes #30957 ### Tested the behaviour in the following platforms - [x] Android - [x] Windows - [ ] iOS - [ ] Mac ### Output Screenshot Before Issue Fix | After Issue Fix | |----------|----------| |<image width="300" height="150" alt="Before Fix" src="https://github.com/user-attachments/assets/ff89beda-1093-46fc-9aa6-4df3372f937f">|<image width="300" height="150" alt="After Fix" src ="https://github.com/user-attachments/assets/e3544ed0-7004-4239-8fd8-458e13b88281">|
…oint precision (#31341) <!-- 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 FlexLayout wrap detection uses a floating-point comparison to decide whether a child item fits on the current line: flex_dim < child_size. On Windows (especially at non-integer DPI scaling factors like 1.25x) and on Android (at densities like 2.625x on Pixel 7), the available flex dimension can be computed fractionally smaller than the child's measured size due to rounding during DPI/density conversion. This causes children that should fit on the current line to be incorrectly moved to a new line. The bug manifests most visibly when buttons dynamically change their FontFamily at runtime, which triggers re-measurement with slightly different sizes. ### Description of Change Introduced a small floating-point tolerance constant (FlexWrapTolerance = 0.1f) in src/Core/src/Layouts/Flex.cs. The wrap line detection check is updated from: `if (layout.flex_dim < child_size)` to: ``` float flex_tolerance = layout.flex_dim + FlexWrapTolerance; if (flex_tolerance < child_size) ``` This tolerance is applied unconditionally across all platforms. Since the value (0.1f) is well below any intentional layout gap (always ≥ 1 device-independent unit), it has no adverse effect on correct wrapping behavior on any platform. ### Key Technical Details **Affected file:** src/Core/src/Layouts/Flex.cs — the shared cross-platform flex layout engine **Constant:** FlexWrapTolerance = 0.1f — accounts for sub-pixel rounding from DPI/density scaling **Platforms affected:** Windows (DPI scaling, e.g., 1.25x) and Android (density, e.g., 2.625 on Pixel 7). iOS/Mac may benefit as a safe cross-platform fix. ### Issues Fixed Fixes #30957 ### Tested the behaviour in the following platforms - [x] Android - [x] Windows - [ ] iOS - [ ] Mac ### Output Screenshot Before Issue Fix | After Issue Fix | |----------|----------| |<image width="300" height="150" alt="Before Fix" src="https://github.com/user-attachments/assets/ff89beda-1093-46fc-9aa6-4df3372f937f">|<image width="300" height="150" alt="After Fix" src ="https://github.com/user-attachments/assets/e3544ed0-7004-4239-8fd8-458e13b88281">|
…oint precision (#31341) <!-- 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 FlexLayout wrap detection uses a floating-point comparison to decide whether a child item fits on the current line: flex_dim < child_size. On Windows (especially at non-integer DPI scaling factors like 1.25x) and on Android (at densities like 2.625x on Pixel 7), the available flex dimension can be computed fractionally smaller than the child's measured size due to rounding during DPI/density conversion. This causes children that should fit on the current line to be incorrectly moved to a new line. The bug manifests most visibly when buttons dynamically change their FontFamily at runtime, which triggers re-measurement with slightly different sizes. ### Description of Change Introduced a small floating-point tolerance constant (FlexWrapTolerance = 0.1f) in src/Core/src/Layouts/Flex.cs. The wrap line detection check is updated from: `if (layout.flex_dim < child_size)` to: ``` float flex_tolerance = layout.flex_dim + FlexWrapTolerance; if (flex_tolerance < child_size) ``` This tolerance is applied unconditionally across all platforms. Since the value (0.1f) is well below any intentional layout gap (always ≥ 1 device-independent unit), it has no adverse effect on correct wrapping behavior on any platform. ### Key Technical Details **Affected file:** src/Core/src/Layouts/Flex.cs — the shared cross-platform flex layout engine **Constant:** FlexWrapTolerance = 0.1f — accounts for sub-pixel rounding from DPI/density scaling **Platforms affected:** Windows (DPI scaling, e.g., 1.25x) and Android (density, e.g., 2.625 on Pixel 7). iOS/Mac may benefit as a safe cross-platform fix. ### Issues Fixed Fixes #30957 ### Tested the behaviour in the following platforms - [x] Android - [x] Windows - [ ] iOS - [ ] Mac ### Output Screenshot Before Issue Fix | After Issue Fix | |----------|----------| |<image width="300" height="150" alt="Before Fix" src="https://github.com/user-attachments/assets/ff89beda-1093-46fc-9aa6-4df3372f937f">|<image width="300" height="150" alt="After Fix" src ="https://github.com/user-attachments/assets/e3544ed0-7004-4239-8fd8-458e13b88281">|
…oint precision (#31341) <!-- 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 FlexLayout wrap detection uses a floating-point comparison to decide whether a child item fits on the current line: flex_dim < child_size. On Windows (especially at non-integer DPI scaling factors like 1.25x) and on Android (at densities like 2.625x on Pixel 7), the available flex dimension can be computed fractionally smaller than the child's measured size due to rounding during DPI/density conversion. This causes children that should fit on the current line to be incorrectly moved to a new line. The bug manifests most visibly when buttons dynamically change their FontFamily at runtime, which triggers re-measurement with slightly different sizes. ### Description of Change Introduced a small floating-point tolerance constant (FlexWrapTolerance = 0.1f) in src/Core/src/Layouts/Flex.cs. The wrap line detection check is updated from: `if (layout.flex_dim < child_size)` to: ``` float flex_tolerance = layout.flex_dim + FlexWrapTolerance; if (flex_tolerance < child_size) ``` This tolerance is applied unconditionally across all platforms. Since the value (0.1f) is well below any intentional layout gap (always ≥ 1 device-independent unit), it has no adverse effect on correct wrapping behavior on any platform. ### Key Technical Details **Affected file:** src/Core/src/Layouts/Flex.cs — the shared cross-platform flex layout engine **Constant:** FlexWrapTolerance = 0.1f — accounts for sub-pixel rounding from DPI/density scaling **Platforms affected:** Windows (DPI scaling, e.g., 1.25x) and Android (density, e.g., 2.625 on Pixel 7). iOS/Mac may benefit as a safe cross-platform fix. ### Issues Fixed Fixes #30957 ### Tested the behaviour in the following platforms - [x] Android - [x] Windows - [ ] iOS - [ ] Mac ### Output Screenshot Before Issue Fix | After Issue Fix | |----------|----------| |<image width="300" height="150" alt="Before Fix" src="https://github.com/user-attachments/assets/ff89beda-1093-46fc-9aa6-4df3372f937f">|<image width="300" height="150" alt="After Fix" src ="https://github.com/user-attachments/assets/e3544ed0-7004-4239-8fd8-458e13b88281">|
## What's Coming .NET MAUI inflight/candidate introduces significant improvements across all platforms with focus on quality, performance, and developer experience. This release includes 153 commits with various improvements, bug fixes, and enhancements. ## Activityindicator - [Android] Fix CollectionView ActivityIndicator not animating after header height change by @Vignesh-SF3580 in #35358 <details> <summary>🔧 Fixes</summary> - [CollectionView items fail to update ActivityIndicator state after header height change](#33780) </details> ## Animation - [Android] Fix Shadow property affecting transform matrix. by @Shalini-Ashokan in #32962 <details> <summary>🔧 Fixes</summary> - [[Android] Applying Shadow property affects the properties in Visual Transform Matrix](#32731) </details> ## API - Add delegate-based alert dialog extensibility convention (no public API changes) by @Redth in #35095 <details> <summary>🔧 Fixes</summary> - [Alert/Dialog system (`DisplayAlert`, `DisplayActionSheet`, `DisplayPromptAsync`) needs a public extensibility point](#34104) </details> ## Blazor - [Android] Fix for BlazorWebView predictive back callback blocks Android back-to-home animation by @BagavathiPerumal in #35538 <details> <summary>🔧 Fixes</summary> - [[Android] BlazorWebView predictive back callback blocks Android back-to-home animation](#35397) </details> - [Android] Fix BlazorWebView back callback can swallow the first Back press when its callback is stale-enabled by @devanathan-vaithiyanathan in #35611 <details> <summary>🔧 Fixes</summary> - [[inflight regression] Android BlazorWebView back callback can swallow the first Back press when its callback is stale-enabled](#35573) </details> ## Border - [Windows] Fixed the ContentView clip is not updated when wrapping inside the Border by @Ahamed-Ali in #30408 <details> <summary>🔧 Fixes</summary> - [[Windows] ContentView clip is not updated when wrapping inside the Border](#30404) </details> - Fix Border.StrokeDashArray leaks dashed Borders when using a shared Application resource by @devanathan-vaithiyanathan in #35544 <details> <summary>🔧 Fixes</summary> - [`Border.StrokeDashArray` leaks dashed Borders when using a shared Application resource](#35492) </details> - [Windows] Border: Add AutomationPeer support by @Vignesh-SF3580 in #35577 <details> <summary>🔧 Fixes</summary> - [Adding AutomationPeers to Windows Borders](#27627) </details> - [Windows] Fixed BoxView improper rendering inside Border by @Dhivya-SF4094 in #28465 <details> <summary>🔧 Fixes</summary> - [[Windows] Issues with BoxView Placement Inside Border](#19668) </details> ## Button - Prevent NullReferenceException in LayoutButton by @GamesAgeddon in #35284 <details> <summary>🔧 Fixes</summary> - [NullReferenceException on iOS in Button.LayoutButton from WrapperView.LayoutSubviews](#31048) </details> - Fix TextColor null reset to restore platform defaults on iOS and Android by @Shalini-Ashokan in #35563 <details> <summary>🔧 Fixes</summary> - [[Windows, Android, iOS & Mac]Button TextColor does not restore to platform default when reset to null after dynamic update](#35513) </details> ## CollectionView - Fix CollectionView grid spacing updates for first row and column by @KarthikRajaKalaimani in #34527 <details> <summary>🔧 Fixes</summary> - [[MAUI] I2_Vertical grid for horizontal Item Spacing and Vertical Item Spacing - horizontally updating the spacing only applies to the second column](#34257) </details> - [MacCatalyst] Fix CollectionView Header/Footer Not Expanding to Content Width by @KarthikRajaKalaimani in #35213 <details> <summary>🔧 Fixes</summary> - [[MacOS][CV2] I8_View header and footer_Horizontal_View - Footer on the right doesn't adapt when resizing the window](#35113) </details> - [iOS/MacCatalyst] Fix IndicatorView not updating when IndicatorSize is changed to default value by @Shalini-Ashokan in #35215 <details> <summary>🔧 Fixes</summary> - [[iOS/MacCatalyst] IndicatorView does not update when IndicatorSize is dynamically changed to the default value](#35214) </details> - CollectionView selecteditem background lost if collectionview (or parent) IsEnabled changed. by @KarthikRajaKalaimani in #31540 <details> <summary>🔧 Fixes</summary> - [CollectionView selecteditem background lost if collectionview (or parent) IsEnabled changed.](#20615) </details> - [iOS/macOS] CollectionView: Fix FlowDirection not working on EmptyView by @Dhivya-SF4094 in #32674 <details> <summary>🔧 Fixes</summary> - [[iOS, MacOS] FlowDirection not working on EmptyView in CollectionView](#32404) - [[iOS, Mac] CollectionView EmptyViewTemplate content text is mirrored when FlowDirection is RightToLeft](#34522) </details> - Fix iOS CollectionView stale layout invalidations by @filipnavara in #35245 <details> <summary>🔧 Fixes</summary> - [[iOS] CollectionView tries to invalidate cells with invalid indexes](#35244) </details> - Fix Android grouped CollectionView header/footer rebind leak by @AdamEssenmacher in #35368 <details> <summary>🔧 Fixes</summary> - [Memory leak when scrolling a CollectionView with IsGrouped=true](#17698) </details> - [Windows] Fix for Item should scrolled based on the GroupHeaderTemplate by @SuthiYuvaraj in #28074 <details> <summary>🔧 Fixes</summary> - [I9_Scroll by object for grouped data - The group name is always pined at the top after clicking 'Scroll to Proboscis Monkey' button](#27922) </details> - [Android] Fix ScrollTo regression when IsGrouped true on CollectionView by @SubhikshaSf4851 in #35356 <details> <summary>🔧 Fixes</summary> - [[10.0.60] ScrollTo(0) not working anymore on CollectionView when IsGrouped="True"](#35313) </details> - [Android] Fix CollectionView scrolling performance regression by @devanathan-vaithiyanathan in #35379 <details> <summary>🔧 Fixes</summary> - [[10.0.60] CollectionView scrolling performance regression](#35344) </details> - Optimize parent dynamic resource refresh by @AdamEssenmacher in #35408 <details> <summary>🔧 Fixes</summary> - [Memory usage increases when scrolling collectionview if resources count is more than 191](#22053) </details> - Fix CI failure for CollectionView Scrolling Feature Tests due to PR #35379 by @devanathan-vaithiyanathan in #35536 - [iOS & Mac] CarouselViewController2 leaks on iOS/MacCatalyst due to unremoved orientation notification observer by @SubhikshaSf4851 in #35532 <details> <summary>🔧 Fixes</summary> - [CarouselViewController2 leaks on iOS/MacCatalyst due to unremoved orientation notification observer](#35472) </details> - Fix CollectionView.SelectedItems leaks popped views when bound to a retained ObservableCollection by @HarishwaranVijayakumar in #35558 <details> <summary>🔧 Fixes</summary> - [`CollectionView.SelectedItems` leaks popped views when bound to a retained `ObservableCollection`](#35497) </details> - Fix for Android - Dynamic Updates to CollectionView Header/Footer and Templates Are Not Displayed by @SuthiYuvaraj in #28904 <details> <summary>🔧 Fixes</summary> - [Android - Dynamic Updates to CollectionView Header/Footer and Templates Are Not Displayed](#28676) </details> - [Windows] Fix CarouselView EmptyView display when filtering to zero items by @Shalini-Ashokan in #29247 <details> <summary>🔧 Fixes</summary> - [[Windows] [Scenario Day] EmptyView using Template displayed at the same time as the content](#7150) </details> - [Android/iOS] Fix IsEnabled=False on CollectionView not working by @devanathan-vaithiyanathan in #27749 <details> <summary>🔧 Fixes</summary> - [[iOS/Android] CollectionView IsEnabled Not Working](#27770) </details> - Fix CarouselView.Loop property does not update dynamically and fails to maintain the scroll position when the loop value is changed at runtime by @devanathan-vaithiyanathan in #29527 <details> <summary>🔧 Fixes</summary> - [[Android] CarouselView.Loop = false causes crash on Android when changed at runtime](#29411) - [Loop Binding in CarouselView Not Updating Dynamically at Runtime](#29449) </details> - [iOS / Mac] Fix CollectionView.ScrollTo(index) silently failing whenIsGrouped="True" by @Dhivya-SF4094 in #35609 <details> <summary>🔧 Fixes</summary> - [CollectionView.ScrollTo(index) doesn't work correctly when IsGrouped="True" on iOS, MacCatalyst, and Windows](#35326) </details> - Fix Android nested carousel scrolling by @AdamEssenmacher in #35656 <details> <summary>🔧 Fixes</summary> - [Vertical scrolling not working for CarouselView and CustomLayouts](#7814) </details> - [Inflight regression] Fixed Test failures ModalTabbedPagePushAsyncShouldOverlayBottomNavigationView and GroupedCollectionViewScrollToIndexScrollsToCorrectItem by @Dhivya-SF4094 in #35823 - Fix CarouselView tests fail in June 8 Candidate by @devanathan-vaithiyanathan in #35825 ## Core - Reduce allocations on AnimationManager by @pictos in #35612 <details> <summary>🔧 Fixes</summary> - [AnimationManager is allocating a lot](#35654) </details> ## Core Lifecycle - Fix device test memory by @pictos in #35487 <details> <summary>🔧 Fixes</summary> - [Memory leak Device.Test pass with false positive](#35485) </details> ## Datepicker - Fix MacCatalyst DatePicker focus handling by @AdamEssenmacher in #35553 <details> <summary>🔧 Fixes</summary> - [[mauipalooza] DatePicker focus only works first time](#5947) </details> ## DateTimePicker - [Android] Fix DatePicker dialog dismisses after the device is rotated by @HarishwaranVijayakumar in #34980 <details> <summary>🔧 Fixes</summary> - [[Android] [Regression] DatePicker dialog dismisses after the device is rotated](#34973) </details> ## Docs - doc: Add paragraph to README.md explaining how to fetch the `maui` project templates by @durandt in #34561 ## Drawing - [Android] Fix LinearGradientBrush rendering as opaque black box by @SubhikshaSf4851 in #35299 <details> <summary>🔧 Fixes</summary> - [[Regression] LinearGradientBrush broken on Android in 10.0.60](#35280) - [10.0.60 breaks transparency on Brushes (on Android?)](#35354) </details> - Fix polygon points collection handler leak by @AdamEssenmacher in #35526 <details> <summary>🔧 Fixes</summary> - [PolygonHandler and PolylineHandler leak when Points is replaced before disconnect](#35387) </details> ## Editor - [iOS] Fix Editor losing scrollability after rotation when CharacterSpacing is applied by @Vignesh-SF3580 in #35309 <details> <summary>🔧 Fixes</summary> - [[.NET 10][iOS] D2 - Editor can't be scrolled after rotating simulator.](#35114) </details> - [Inflight/Candidate][iOS & Mac] Fix for Editor height inconsistency when VerticalTextAlignment is Center or End on iOS and MacCatalyst by @BagavathiPerumal in #35662 <details> <summary>🔧 Fixes</summary> - [[MAUI] D13_Customize_Text_Alignment - Text Editor Height is not consistent](#35615) </details> ## Entry - [iOS/Mac] Fix Entry clear button retaining tint color after TextColor is reset to null by @SyedAbdulAzeemSF4852 in #35177 <details> <summary>🔧 Fixes</summary> - [[iOS/Mac]Entry ClearButtonVisibility color does not reset when TextColor is set to null](#35076) </details> - [iOS/MacCatalyst] Fix Entry clear button appearing dimmed compared to TextColor by @SyedAbdulAzeemSF4852 in #35541 <details> <summary>🔧 Fixes</summary> - [[MacCatalyst] [Entry] ClearButtonVisibility color appears dimmed compared to TextColor](#35517) </details> - Fix pill-shaped focus ring on macOS 26 by @Dhivya-SF4094 in #35393 <details> <summary>🔧 Fixes</summary> - [.Net 10 Picker item not centered and wrong focus outline of Entry on Mac](#34899) </details> - Fix Entry select all text on refocus not working on WinUI by @kubaflo in #35383 ## Essentials - [Android] Fix Capture video crashes after stopping recording on Android 12 by @HarishwaranVijayakumar in #35638 <details> <summary>🔧 Fixes</summary> - [Capture video crashes after stopping recording on Android 12](#28891) </details> - [Essentials] Browser.OpenAsync(External): drop visibility-filtered ResolveActivity pre-check by @Kebechet in #35652 <details> <summary>🔧 Fixes</summary> - [Browser.OpenAsync(External) on Android throws FeatureNotSupportedException for verified App Link owner URLs even with documented <queries> fix applied](#35651) </details> ## Essentials Texttospeech - [Mac, iOS, Windows] Fix for inconsistent Text-to-Speech rate behavior by @HarishwaranVijayakumar in #32850 <details> <summary>🔧 Fixes</summary> - [[Essentials] TTS rate](#32492) </details> ## Flyoutpage - [iOS/Mac] Fix FlyoutPage RTL FlowDirection is not working by @devanathan-vaithiyanathan in #34831 <details> <summary>🔧 Fixes</summary> - [[iOS/Mac] FlyoutPage RTL FlowDirection is not working properly](#34830) </details> - [Android] Fix for Android 16 Back button is not working after command from FlyoutPage by @BagavathiPerumal in #35196 <details> <summary>🔧 Fixes</summary> - [Android: BackButton on Android 16 not working after command from FlyOutPage](#33508) </details> ## Gestures - Fix DragGestureRecognizer.DropCompleted event not firing in Android platform by @KarthikRajaKalaimani in #35179 <details> <summary>🔧 Fixes</summary> - [[Android] DragGestureRecognizer.DropCompleted event not firing](#17554) </details> - Windows: Ensure layouts without background participate in hit testing by @jpd21122012 in #34364 <details> <summary>🔧 Fixes</summary> - [[Windows] TapGestureRecognizer does NOT work on a ContentView without Background](#32279) </details> - [iOS] Fix VoiceOver dropping child labels on layouts with SemanticProperties.Hint or TapGestureRecognizer by @Vignesh-SF3580 in #35590 <details> <summary>🔧 Fixes</summary> - [[iOS] VoiceOver does not correctly describe View with GestureRecognizers](#34380) </details> ## Hybridwebview - Fix RemovePossibleQueryString to also strip URL fragments by @kubaflo in #35551 <details> <summary>🔧 Fixes</summary> - [HybridWebViewQueryStringHelper.RemovePossibleQueryString removes '?' but not other special characters e.g. '#'](#31472) </details> - [Revert] - [Windows] Fix WebView blank rendering when used with HybridWebView by @SubhikshaSf4851 in #35814 ## Image - Avoid image source layout invalidation for fixed-size views by @AdamEssenmacher in #35369 <details> <summary>🔧 Fixes</summary> - [Image source swaps thrash layout under fixed constraints, tanking frame rate when scrolling virtualized collections](#32457) </details> - [Windows] Fix Image layout inconsistency caused by async decode race in GetDesiredSize by @praveenkumarkarunanithi in #34699 <details> <summary>🔧 Fixes</summary> - [[Windows] Image cropping produces inconsistent results when window is minimized or resized](#32393) </details> - [Testing] Include more testing around Windows Image Aspect recent fixes by @kubaflo in #35620 <details> <summary>🔧 Fixes</summary> - [[Testing] Include more testing around Windows Image Aspect recent fixes](#31686) </details> - Revert PR #30068 — Fix FontImageSource centering regression on Windows by @Shalini-Ashokan in #35642 <details> <summary>🔧 Fixes</summary> - [[Windows] Image with FontImageSource is not centered and gets clipped when WidthRequest/HeightRequest equals FontImageSource Size](#35618) </details> - [Android] Fix screenshot from WebView content not working by @kubaflo in #35384 <details> <summary>🔧 Fixes</summary> - [[Android] Loading the captured screenshot from webview content to Image control does not visible](#30010) </details> ## Label - Improve label mapping performance and ensure complete coverage including ToPlatform and subsequent property changes by @Tamilarasan-Paranthaman in #31159 - Fix for Label.FormattedText leaks labels when shared FormattedString is stored in Application.Resources by @BagavathiPerumal in #35582 <details> <summary>🔧 Fixes</summary> - [`Label.FormattedText` leaks labels when shared `FormattedString` is stored in `Application.Resources`](#35495) </details> - [iOS] Fix Label Span formatting test failures on candidate branch by @Vignesh-SF3580 in #35815 ## Layout - [iOS, Mac] Fix Item spacing not properly applied between items in Horizontal LinearItemsLayout by @Dhivya-SF4094 in #35445 <details> <summary>🔧 Fixes</summary> - [[CollectionView2] Item spacing not properly applied between items in Horizontal LinearItemsLayout](#35429) </details> - [Windows] Add Automation Id support for Layouts. by @SubhikshaSf4851 in #35562 <details> <summary>🔧 Fixes</summary> - [[Windows] AutomationId does not work for ContentView, Layouts and controls that inherit them](#4715) </details> - Avoid layout diagnostics allocations without listeners by @AdamEssenmacher in #35475 <details> <summary>🔧 Fixes</summary> - [MAUI 10 layout diagnostics no-consumer path is not zero-allocation](#35473) </details> - [Windows/Android] FlexLayout: Fix wrap misalignment due to floating-point precision by @SuthiYuvaraj in #31341 <details> <summary>🔧 Fixes</summary> - [FlexLayout Wrap Misalignment with Dynamically-Sized Buttons in .NET MAUI](#30957) </details> ## Listview - Fix Binding for ListView.IsRefreshing by @bill2004158 in #28516 <details> <summary>🔧 Fixes</summary> - [Bind ListView.IsRefreshing is not work.](#28514) </details> ## Map - Fix iOS/Catalyst MapPool retention with MapElements by @AdamEssenmacher in #35480 <details> <summary>🔧 Fixes</summary> - [iOS/Mac Catalyst MapHandler leaks MAUI Map views and MapElements through MapPool](#35479) </details> - Fix Android map view lifecycle cleanup by @AdamEssenmacher in #35476 <details> <summary>🔧 Fixes</summary> - [Navigating to a page with Maps multiple times Increase RAM Usage but doesn't reduce it back after navigating back](#15257) </details> - Fix Android map element options retention by @AdamEssenmacher in #35634 <details> <summary>🔧 Fixes</summary> - [[Regression] [Android] [Maps] Map locks up after rendering 50 Polylines](#20502) </details> ## Menubar - [MacCatalyst] Fix KeyboardAccelerator with Cmd+Shift modifiers breaks entire MenuBarItem on Mac Catalyst by @KarthikRajaKalaimani in #35318 <details> <summary>🔧 Fixes</summary> - [[Bug] KeyboardAccelerator with Cmd+Shift modifiers breaks entire MenuBarItem on Mac Catalyst](#35279) </details> ## Navigation - [iOS, Mac] Fix OnBackButtonPressed not invoked for NavigationPage and Shell by @Dhivya-SF4094 in #35072 <details> <summary>🔧 Fixes</summary> - [On Screen Back Button Does Not Fire OnBackButtonPressed in Android](#9095) - [ContentPage's OnBackButtonPressed not invoked on iOS and MacCatalyst](#8296) </details> - Fix Android stale ContainerView root leak by @AdamEssenmacher in #35372 <details> <summary>🔧 Fixes</summary> - [Android: Stale ContainerView retains replaced FlyoutPage graph](#35371) </details> - [Android] Fix for predictive back-to-home animation blocked by unconditional back callback registration by @BagavathiPerumal in #35223 <details> <summary>🔧 Fixes</summary> - [OnBackInvokedCallbacks block back-to-home animation](#34594) - [Migrate to OnBackPressedCallback](#24752) </details> - Revert [Android, iOS] - Flyout icon should remain visible when a page is pushed onto a NavigationPage or Shell page with the back button disabled. by @praveenkumarkarunanithi in #35604 ## Picker - [iOS] Fix Picker CharacterSpacing lost after item selection when Title is set by @SyedAbdulAzeemSF4852 in #34974 <details> <summary>🔧 Fixes</summary> - [[iOS] Picker loses CharacterSpacing after item selection when Title is set](#34971) </details> - [iOS] Fix Picker CharacterSpacing ignored on initial load by @SyedAbdulAzeemSF4852 in #34957 <details> <summary>🔧 Fixes</summary> - [[iOS] Picker ignores CharacterSpacing on initial load](#34955) </details> - [Windows] Fix for Picker CharacterSpacing Not Being Applied to Title and Dropdown Items by @SyedAbdulAzeemSF4852 in #30612 <details> <summary>🔧 Fixes</summary> - [[Windows] Picker CharacterSpacing property not applied to Title and PickerItems text](#30464) </details> - Fix Picker SelectedIndex deferred initialization by @AdamEssenmacher in #35629 <details> <summary>🔧 Fixes</summary> - [Picker Attribute "SelectedIndex" Not being respected on page load on Android?](#9150) </details> ## Progressbar - Fix iOS ProgressBar bounding box by @AdamEssenmacher in #35507 <details> <summary>🔧 Fixes</summary> - [[iOS] ProgressBar and Label don't correctly obey height and width at the core level](#7935) </details> ## RadioButton - [Windows, Android] Fix Border Color and Border Width Not applying for Radio Button by @HarishwaranVijayakumar in #35616 <details> <summary>🔧 Fixes</summary> - [[Windows, Android] Border Color and Border Width Not applying for Radio Button.](#35587) </details> - [inflight/current] Fixes a CS0111 build failure in RadioButton.cs caused by a duplicate OnPropertyChanged override by @HarishwaranVijayakumar in #35631 - Revert - Fix TalkBack not correctly narrating RadioButtons with Content by @devanathan-vaithiyanathan in #35625 <details> <summary>🔧 Fixes</summary> - [[Android] MissingMethodException AccessibilityNodeInfoCompat.set_Checked(bool) on 10.0.70 due to AndroidX.Core 1.17 breaking change](#35584) </details> ## Refreshview - [Windows] Fix RefreshView IsRefreshing property not working while binding by @devanathan-vaithiyanathan in #34845 <details> <summary>🔧 Fixes</summary> - [[Windows] RefreshView IsRefreshing property not working while binding](#30535) </details> - [Android] Fix for RefreshView triggering pull-to-refresh when scrolling inside a WebView with internal scrollable content by @BagavathiPerumal in #34614 <details> <summary>🔧 Fixes</summary> - [[Android] RefreshView triggers pull-to-refresh immediately when scrolling up inside a WebView](#33510) </details> ## SafeArea - [Android] Fix bottom safe area padding dropping to zero when keyboard is shown by @praveenkumarkarunanithi in #35084 <details> <summary>🔧 Fixes</summary> - [[Android] Bottom insets issues when keyboard is shown.](#32871) </details> - Gate SafeArea inset listeners in recycler items by @AdamEssenmacher in #35664 <details> <summary>🔧 Fixes</summary> - [[10.0.60] CollectionView scrolling performance regression](#35344) </details> ## ScrollView - [Windows] Fix COMException when restoring a ScrollView as ContentPage.Content after swapping it out by @Vignesh-SF3580 in #35360 <details> <summary>🔧 Fixes</summary> - [COMException when clone a page's content to a object and set it back later in mainthread on Windows](#35277) </details> - Fix - ScrollView.ScrollToAsync(x, y, animated) doesn't work when called from Page.OnAppearing by @Shalini-Ashokan in #35395 <details> <summary>🔧 Fixes</summary> - [[iOS] ScrollView.ScrollToAsync(x, y, animated) doesn't work when called from Page.OnAppearing](#31177) </details> ## Searchbar - [Android] Fix SearchBar IME full-screen extract mode in landscape orientation by @SubhikshaSf4851 in #35197 <details> <summary>🔧 Fixes</summary> - [[Android] Investigate SearchBar presentation in horizontal screen orientation ](#14708) </details> - [iOS 26] Fix SearchBar layout spacing issues for small HeightRequest values by @devanathan-vaithiyanathan in #35347 <details> <summary>🔧 Fixes</summary> - [Spacing problem with maui 10.0.60 iOS](#35286) </details> ## SearchBar - [Windows] Fix SearchHandler does not focus when ShowSoftInputAsync is called by @praveenkumarkarunanithi in #35079 <details> <summary>🔧 Fixes</summary> - [[Windows] SearchHandler.ShowSoftInputAsync() does not focus the SearchHandler](#34930) </details> ## Shell - Fix Android layout jump when navigating with IME open and NavBarIsVisible=false by @jpd21122012 in #34621 <details> <summary>🔧 Fixes</summary> - [Shell page without NavBar jumping when navigating with keyboard open](#34584) </details> - [Android] Add defensive not null check to SearchHandlerAppearanceTracker.FocusChange by @Transis-Felipe in #29939 - [Android] Fix for Shell colors change before navigation completes on Android in .NET 10 by @BagavathiPerumal in #35295 <details> <summary>🔧 Fixes</summary> - [Shell colors change before navigation completes on Android in .NET 10](#35060) </details> - [Windows] Fix Shell FlyoutItem not taking full width by @SubhikshaSf4851 in #35131 <details> <summary>🔧 Fixes</summary> - [MAUI WinUI Grids don't render properly in flyout menu](#19542) - [[Windows] [.NET 8 RC2] FlyoutItem Backgroundcolor Is not fully displaying](#18238) </details> - [Android, iOS, Catalyst] Fix SearchHandler.BackgroundColor cannot be reset to null by @HarishwaranVijayakumar in #35224 <details> <summary>🔧 Fixes</summary> - [[Android, iOS, Catalyst] SearchHandler.BackgroundColor cannot be reset to null](#35088) </details> - Fix for ApplyQueryAttributes being called on non-destination pages during back navigation by @BagavathiPerumal in #35392 <details> <summary>🔧 Fixes</summary> - [ApplyQueryAttributes gets called for not activated (navigated to) page on back](#35183) </details> - [Android] Fix Shell flyout background to follow Material 3 theme colors by @SyedAbdulAzeemSF4852 in #35148 <details> <summary>🔧 Fixes</summary> - [[Android] Shell Flyout ignores Material 3 surface color when UseMaterial3 is enabled](#35147) </details> - [Android] Fix Shell.FlyoutHeader background incorrect by @SyedAbdulAzeemSF4852 in #35489 <details> <summary>🔧 Fixes</summary> - [[Android] Shell.FlyoutHeader background is incorrect](#35416) </details> - [iOS/MacCatalyst] Fix Shell.BackgroundColor not applied to bottom TabBar by @Shalini-Ashokan in #35545 <details> <summary>🔧 Fixes</summary> - [[MacCatalyst] Shell.BackgroundColor not applied to bottom TabBar](#35380) - [[Catalyst] Shell.TabBarBackgroundColor is not applied](#35381) </details> - [Android] Fix Shell FlyoutIcon tint loss after navigation by @SyedAbdulAzeemSF4852 in #35561 <details> <summary>🔧 Fixes</summary> - [[Android] The flyout icon loses colours](#35390) </details> - [iOS] Fix Shell - opened keyboard on modal page shifts parent page/frame behind modal after update to 10.0.60 by @KarthikRajaKalaimani in #35559 <details> <summary>🔧 Fixes</summary> - [[iOS] Shell - opened keyboard on modal page shifts parent page/frame behind modal after update to 10.0.60](#35401) </details> - Fix intermediate pages not receiving query parameters in multi-page Shell navigation by @mattleibow in #35432 <details> <summary>🔧 Fixes</summary> - [Shell GoToAsync: no way to pass query parameters to intermediate pages in multi-segment navigation](#35107) </details> - [Windows] Fix Shell title bar overlap with window controls in RTL mode by @Shalini-Ashokan in #33109 <details> <summary>🔧 Fixes</summary> - [[Windows] Binding RTL FlowDirection in Shell causes Flyout MenuIcon and native window controls to overlap](#32476) </details> - [macOS] Fix IsEnabled property false not working on MenuBarItem by @devanathan-vaithiyanathan in #35546 <details> <summary>🔧 Fixes</summary> - [[macOS] IsEnabled property false not working on MenuBarItem](#34038) </details> - Fix Android Shell top inset when nav bar is hidden by @ne0rrmatrix in #35555 <details> <summary>🔧 Fixes</summary> - [wrong statusbar height when Android device has a notch](#35103) </details> - Fix Changing Content property of ShellContent doesn't change visual content by @devanathan-vaithiyanathan in #34630 <details> <summary>🔧 Fixes</summary> - [Changing Content property of ShellContent doesn't change visual content. ](#12669) </details> - Fixed a NullReferenceException when starting application with empty shell on Windows by @Shalini-Ashokan in #28879 <details> <summary>🔧 Fixes</summary> - [NullReferenceException when starting application with empty shell on Windows](#21562) - [Using SelectionChangedCommand with CollectionView in Shell.FlyoutContent results in Win32 Unhandled Exception](#10041) </details> ## Slider - [iOS] Slider: Scale ThumbImageSource to match default thumb size by @NirmalKumarYuvaraj in #34184 <details> <summary>🔧 Fixes</summary> - [[Slider] MAUI Slider thumb image is big on android](#13258) </details> ## Stepper - Fix iOS 26 Stepper overlap in landscape by @AdamEssenmacher in #35374 <details> <summary>🔧 Fixes</summary> - [[.NET10] D10-The number and buttons overlap after rotating the simulator.](#35211) </details> ## SwipeView - Fix SwipeViews with invoked properties crash the app in Release mode by @BagavathiPerumal in #35208 <details> <summary>🔧 Fixes</summary> - [[iOS/Catalyst] Swipeviews with invoked properties crash the app in Release](#18055) </details> - Fix SwipeItemView command leak by @AdamEssenmacher in #35510 <details> <summary>🔧 Fixes</summary> - [`SwipeItemView.Command` leaks row views and command parameters through `CanExecuteChanged`](#35498) </details> - [iOS/Android] Fix SwipeItem.IsVisible not refreshing native swipe items when binding changes by @SyedAbdulAzeemSF4852 in #35217 <details> <summary>🔧 Fixes</summary> - [SwipeItem.IsVisible doesn't properly refresh the native swipe items when the binding value changes dynamically](#34832) </details> - Fix SwipeView memory leak when SwipeItems are reused or replaced by @Vignesh-SF3580 in #35539 <details> <summary>🔧 Fixes</summary> - [SwipeView leaks when SwipeItems are reused or replaced](#35481) </details> - Fix SwipeItem IconImageSource color handling and rendering across platforms by @Shalini-Ashokan in #35632 <details> <summary>🔧 Fixes</summary> - [[Android] SwipeItem IconImageSource should allow more configuration](#23074) </details> ## Switch - [Android/Windows] Fix RadioButton gradient not clearing when switching background by @Shalini-Ashokan in #34997 <details> <summary>🔧 Fixes</summary> - [RadioButton Background does not reset when set to null at runtime](#34993) </details> - [Windows] Fix "PlatformView cannot be null here" exception during handler disconnect by @kubaflo in #35314 <details> <summary>🔧 Fixes</summary> - ["PlatformView cannot be null here" Exception in Switch control [Windows]](#27101) </details> - [iOS 26] Fix Switch ThumbColor and OffColor not applied on initial load by @SyedAbdulAzeemSF4852 in #35400 <details> <summary>🔧 Fixes</summary> - [iOS 26 Switch default color for Off and On is incorrect + Off Color is not applied at start + Thumb Colors is not applied](#35257) </details> - [Android] Fix AppBar flicker on CheckBox/Switch toggle with Material 3 by @Dhivya-SF4094 in #35181 <details> <summary>🔧 Fixes</summary> - [[Android] AppBar flicker while changing the CheckBox or Switch state after scrolling in Material 3](#35180) </details> - [Android] Fix Switch Shadow Does Not Follow Thumb when Toggle On or Off by @Dhivya-SF4094 in #35623 <details> <summary>🔧 Fixes</summary> - [[Android] Switch Shadow Does Not Follow Thumb when Toggle On or Off](#30046) </details> ## TabbedPage - [Android] Fix TabbedPage truncating tab titles instead of scrolling by @Shalini-Ashokan in #35086 <details> <summary>🔧 Fixes</summary> - [Maui migrating Xamarin to Maui - Tabbed Page Scroll Issue - Tabs are not scrolling](#16470) </details> - [Android] Fix BottomNavigationView remaining visible for TabbedPage inside modal NavigationPage after PushAsync by @Dhivya-SF4094 in #35359 <details> <summary>🔧 Fixes</summary> - [Android TabbedPage inside Modal Navigation does not overlay BottomNavigationView after PushAsync in .NET MAUI 10.0.60](#35331) </details> - [Android & iOS] TabbedPage leaks with shared GradientBrush. by @SubhikshaSf4851 in #35543 <details> <summary>🔧 Fixes</summary> - [TabbedPage leaks renderer/manager when BarBackground uses shared GradientBrush resource](#35469) </details> ## Templates - Bumps Syncfusion.Maui.Toolkit dependency to version 1.0.10 by @PaulAndersonS in #35608 ## Toolbar - Fix Android app bar inset background coloring by @ne0rrmatrix in #35601 <details> <summary>🔧 Fixes</summary> - [Android Edge-to-Edge: Shell and NavigationPage Top Bar colour is not used for status bar.](#35568) </details> ## Tooling - Add default .gitignore to MAUI project templates by @davidortinau in #34862 <details> <summary>🔧 Fixes</summary> - [Add a gitignore file to the Maui template in VS 2022](#4131) </details> - Fix: Propagate AdditionalProperties from ProjectReference in ResizetizeCollectItems by @mattleibow in #35575 <details> <summary>🔧 Fixes</summary> - [Resizetizer GetMauiItems does not propagate ProjectReference AdditionalProperties](#35574) </details> ## WebView - [Windows] Fix WebView blank rendering when used with HybridWebView by @SubhikshaSf4851 in #35092 <details> <summary>🔧 Fixes</summary> - [[Windows] WebView Regression from NET9 to NET10](#34558) </details> - Fix AOT integration test failures: suppress IL3050/IL2026 for HybridWebViewHandler in AddControlsHandlers by @mattleibow via @Copilot in #34868 - Fix Android activity result callback leak by @AdamEssenmacher in #35436 <details> <summary>🔧 Fixes</summary> - [Android WebView file chooser callbacks leak via ActivityResultCallbackRegistry](#35405) </details> - [Windows] Fix WebView Does Not Inherit App Theme by @devanathan-vaithiyanathan in #35037 <details> <summary>🔧 Fixes</summary> - [WebView on Windows Does Not Inherit App Theme](#34823) </details> - Fix for WebView leaks when reusing a shared WebViewSource by @BagavathiPerumal in #35524 <details> <summary>🔧 Fixes</summary> - [WebView leaks when reusing a shared WebViewSource](#35483) </details> - Destroy Android WebView on handler disconnect by @AdamEssenmacher in #35552 <details> <summary>🔧 Fixes</summary> - [Right way to dispose page with WebView](#18021) </details> ## Xaml - Fix: Enable VisualStateManager to set Style property dynamically by @Shalini-Ashokan in #33389 <details> <summary>🔧 Fixes</summary> - [Setting the `Style` property using the `VisualStateManager` within a Style resource does not work](#17175) </details> - Fix Implicit parameter conversion from integer to byte fails with source generated XAML by @KarthikRajaKalaimani in #35444 <details> <summary>🔧 Fixes</summary> - [Implicit parameter conversion from integer to byte fails with source generated XAML](#35396) </details> <details> <summary>🔧 Infrastructure (3)</summary> - Fix: Build fails when appicon is an empty (but valid) SVG by @Shalini-Ashokan in #35305 <details> <summary>🔧 Fixes</summary> - [Build fails when appicon is an empty (but valid) svg after upgrade to 10.0.60](#35293) </details> - [inflight/current] Fix CS0111 duplicate GetNativeCharacterSpacing in PickerHandlerTests.iOS by @SyedAbdulAzeemSF4852 in #35419 - Update WinAppSDK to 1.8.260508005 by @kubaflo in #35678 </details> <details> <summary>🧪 Testing (3)</summary> - Backport Test Fixes and Snapshots from SR to Inflight Branch by @Tamilarasan-Paranthaman in #35499 - Fix hardcoded version of Microsoft.DotNet.XHarness.TestRunners.Xunit in test projects by @akoeplinger in #29905 - [Testing] Fixed Build error on inflight/ candidate PR 35716 by @HarishKumarSF4517 in #35730 </details> <details> <summary>🏠 Housekeeping (1)</summary> - [HouseKeeping] Fix inconsistant namespace in HostApp by @NirmalKumarYuvaraj in #35210 </details> <details> <summary>📦 Other (8)</summary> - Add .cab and ReconnectModal.razor.js to signing config by @jesuszarate in #35026 - Fix typo in Clipboard.shared.cs by @Deadpikle in #35316 - Fix single modifier for NSMenuItem accelerators by @jeremy-visionaid in #35351 - Avoid unnecessary LINQ enumerations by @jeremy-visionaid in #35272 - [Testing] Replace retryDelay with retryTimeout in UI tests by @kubaflo in #35367 - Replace JavaFinalize() with Dispose(bool) in GenericAnimatorListener by @jonathanpeppers in #35548 - Fix incorrect SDK provisioning commands in integration-tests instructions by @davidnguyen-tech in #34992 - Fix VisualElement.ChangeVisualState() gets stuck in Selected state by @Dhivya-SF4094 in #35421 <details> <summary>🔧 Fixes</summary> - [VisualElement's ChangeVisualState gets stuck in Selected state](#35399) </details> </details> <details> <summary>📝 Issue References</summary> Fixes #4131, Fixes #4715, Fixes #5947, Fixes #7150, Fixes #7814, Fixes #7935, Fixes #8296, Fixes #9095, Fixes #9150, Fixes #10041, Fixes #12669, Fixes #13258, Fixes #14708, Fixes #15257, Fixes #16470, Fixes #17175, Fixes #17554, Fixes #17698, Fixes #18021, Fixes #18055, Fixes #18238, Fixes #19542, Fixes #19668, Fixes #20502, Fixes #20615, Fixes #21562, Fixes #22053, Fixes #23074, Fixes #24752, Fixes #27101, Fixes #27627, Fixes #27770, Fixes #27922, Fixes #28514, Fixes #28676, Fixes #28891, Fixes #29411, Fixes #29449, Fixes #30010, Fixes #30046, Fixes #30404, Fixes #30464, Fixes #30535, Fixes #30957, Fixes #31048, Fixes #31177, Fixes #31472, Fixes #31686, Fixes #32279, Fixes #32393, Fixes #32404, Fixes #32457, Fixes #32476, Fixes #32492, Fixes #32731, Fixes #32871, Fixes #33508, Fixes #33510, Fixes #33780, Fixes #34038, Fixes #34104, Fixes #34257, Fixes #34380, Fixes #34522, Fixes #34558, Fixes #34584, Fixes #34594, Fixes #34823, Fixes #34830, Fixes #34832, Fixes #34899, Fixes #34930, Fixes #34955, Fixes #34971, Fixes #34973, Fixes #34993, Fixes #35060, Fixes #35076, Fixes #35088, Fixes #35103, Fixes #35107, Fixes #35113, Fixes #35114, Fixes #35147, Fixes #35180, Fixes #35183, Fixes #35211, Fixes #35214, Fixes #35244, Fixes #35257, Fixes #35277, Fixes #35279, Fixes #35280, Fixes #35286, Fixes #35293, Fixes #35313, Fixes #35326, Fixes #35331, Fixes #35344, Fixes #35354, Fixes #35371, Fixes #35380, Fixes #35381, Fixes #35387, Fixes #35390, Fixes #35396, Fixes #35397, Fixes #35399, Fixes #35401, Fixes #35405, Fixes #35416, Fixes #35429, Fixes #35469, Fixes #35472, Fixes #35473, Fixes #35479, Fixes #35481, Fixes #35483, Fixes #35485, Fixes #35492, Fixes #35495, Fixes #35497, Fixes #35498, Fixes #35513, Fixes #35517, Fixes #35568, Fixes #35573, Fixes #35574, Fixes #35584, Fixes #35587, Fixes #35615, Fixes #35618, Fixes #35651, Fixes #35654 </details> **Full Changelog**: main...inflight/candidate
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
FlexLayout wrap detection uses a floating-point comparison to decide whether a child item fits on the current line: flex_dim < child_size. On Windows (especially at non-integer DPI scaling factors like 1.25x) and on Android (at densities like 2.625x on Pixel 7), the available flex dimension can be computed fractionally smaller than the child's measured size due to rounding during DPI/density conversion. This causes children that should fit on the current line to be incorrectly moved to a new line.
The bug manifests most visibly when buttons dynamically change their FontFamily at runtime, which triggers re-measurement with slightly different sizes.
Description of Change
Introduced a small floating-point tolerance constant (FlexWrapTolerance = 0.1f) in src/Core/src/Layouts/Flex.cs. The wrap line detection check is updated
from:
if (layout.flex_dim < child_size)to:
This tolerance is applied unconditionally across all platforms. Since the value (0.1f) is well below any intentional layout gap (always ≥ 1 device-independent unit), it has no adverse effect on correct wrapping behavior on any platform.
Key Technical Details
Affected file: src/Core/src/Layouts/Flex.cs — the shared cross-platform flex layout engine
Constant: FlexWrapTolerance = 0.1f — accounts for sub-pixel rounding from DPI/density scaling
Platforms affected: Windows (DPI scaling, e.g., 1.25x) and Android (density, e.g., 2.625 on Pixel 7). iOS/Mac may benefit as a safe cross-platform fix.
Issues Fixed
Fixes #30957
Tested the behaviour in the following platforms
Output Screenshot