[iOS] Fixed CollectionView Scroll Jitter for TextType HTML Labels#34383
Conversation
|
🚀 Dogfood this PR with:
curl -fsSL https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.sh | bash -s -- 34383Or
iex "& { $(irm https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.ps1) } 34383" |
There was a problem hiding this comment.
Pull request overview
This PR targets iOS scroll “jitter” in CollectionView when Label.TextType="Html" by avoiding the delayed (async) HTML-to-attributed-string update in the CV2 (Items2) cell scenario, while retaining the async dispatch path to avoid the known CV1 crash.
Changes:
- Updates iOS
LabelExtensions.UpdateTextto apply HTML synchronously when the nativeUILabelis hosted inside a CV2 cell. - Adds a UIKit superview-chain helper to detect CV2 cells (
ItemsViewCell2) and uses it to choose the safe update strategy. - Adds an Items2 handler namespace reference to support the CV2-cell detection.
Investigated replacing the namespace reference with GetName() as suggested, but this did not resolve the jittering issue. The using directive is necessary for the implementation to function correctly. Keeping as-is.
Investigated removing the duplicate MapFormatting call. However, removing it causes NSInternalInconsistencyException during fast scrolling — the second call is necessary to keep the cell state consistent under rapid reuse cycles. The double call is intentional as a defensive measure against this crash. Keeping both calls
This bug requires a live device + active scrolling of a CollectionView + visual inspection (or screenshot diff) to reproduce and verify. The visual corruption only manifests during cell reuse under fast scroll velocity — it cannot be triggered or observed in a unit test or static assertion. Manual validation was performed on a physical device confirming the fix resolves the visual corruption. |
🚦 Gate - Test Before and After Fix📊 Expand Full Gate —
|
🤖 AI Summary📊 Expand Full Review —
|
| # | Source | Approach | Test Result | Files Changed | Notes |
|---|---|---|---|---|---|
| PR | PR #34383 | Walk UIKit superview chain to detect CV2 cell; apply HTML synchronously in CV2, async otherwise | LabelExtensions.cs |
Original PR |
🔧 Fix — Analysis & Comparison
Fix Candidates
| # | Source | Approach | Test Result | Files Changed | Notes |
|---|---|---|---|---|---|
| 1 | Attempt 1 (claude-opus-4.6) | RequiresAsyncHtmlUpdate bool property on LabelHandler.iOS.cs; sync is default, CV1 opts in to async |
✅ Build PASS | 2 files (LabelHandler.iOS.cs, LabelExtensions.cs) |
No Items2 dependency; requires LabelHandler change |
| 2 | Attempt 2 (claude-sonnet-4.6) | Reversed conditional: detect CV1 (ItemsViewCell) for async; sync everywhere else |
✅ Build PASS | 1 file (LabelExtensions.cs) |
Imports Handlers.Items (CV1 namespace) instead of CV2; clean — CV1 is the exception |
| 3 | Attempt 3 (gpt-5.3-codex) | Remove async dispatch entirely (HTML always synchronous) | ❌ Build FAIL | 1 file | Build infra issue (missing restore); code approach sound but risky if UpdateTextHtml itself causes CV1 crash |
| 4 | Attempt 4 (gpt-5.4) | Interface IHtmlSyncCapable on ItemsViewCell2; LabelExtensions checks interface; no Items2 namespace in LabelExtensions |
✅ Build PASS | 3 files | Cleanest architecture but most files changed |
| 5 | Attempt 5 (claude-sonnet-4.6, cross-poll) | Split ops: UpdateTextHtml always synchronous; only MapFormatting+InvalidateMeasure async |
✅ Build PASS | 1 file | Most minimal; no detection needed; risk: unknown if UpdateTextHtml causes CV1 crash |
| PR | PR #34383 | Walk UIKit superview chain for ItemsViewCell2; sync in CV2, async elsewhere |
1 file | Adds using Items2 to platform-level code; also has double MapFormatting concern |
Cross-Pollination
| Model | Round | New Ideas? | Details |
|---|---|---|---|
| claude-opus-4.6 | 2 | Yes | Thread-static ambient context flag (try/finally in CV2 cell bind) |
| claude-sonnet-4.6 | 2 | Yes | Split operations: NSAttributedString sync, MapFormatting+InvalidateMeasure async (became Attempt 5) |
| gpt-5.3-codex | 2 | Yes | Per-UILabel token versioning for coalescing stale async updates |
| gpt-5.4 | 2 | Yes | Cache NSAttributedString synchronously during measure; async for rendering only |
| claude-opus-4.6 | 3 | Yes | Deferred-with-flush: store HTML work as pullable delegate; CV2 cells flush in PreferredLayoutAttributesFittingAttributes |
| claude-sonnet-4.6 | 3 | Yes | Walk MAUI virtual tree instead of UIKit hierarchy; interface on CV2 handler |
| gpt-5.3-codex | 3 | Yes | Layout-pass-aware scoped flag in PreferredLayoutAttributesFittingAttributes |
| gpt-5.4 | 3 | Yes | Invalidate _firstItemMeasuredSize CV2 cache for HTML templates |
Exhausted: Yes (max 3 rounds completed; Round 3 ideas are variations of already-explored approaches, increasingly complex)
Selected Fix: Attempt 2 (Reversed conditional — detect CV1 for async, sync everywhere else)
Reason:
- Only 1 file changed (same as PR)
- No new dependencies on
Items2(usesItemsfor the deprecated CV1 path instead) - Architecturally cleaner: the async dispatch is the exception (deprecated CV1 path), not the rule — sync is the default for all modern usage including CV2
- Minimal surface area of change
- Preserves the exact crash-safety guarantee for CV1 with the proven async path
- Attempt 5 (split ops) is also promising but carries uncertainty about whether
UpdateTextHtmlitself contributes to the CV1 crash — Attempt 2 is safer without that uncertainty
📋 Report — Final Recommendation
⚠️ Final Recommendation: REQUEST CHANGES
Phase Status
| Phase | Status | Notes |
|---|---|---|
| Pre-Flight | ✅ COMPLETE | Issue #33065, iOS-only, 1 file changed |
| Gate | No tests detected in PR | |
| Try-Fix | ✅ COMPLETE | 5 attempts, 4 passing (build verification); 3 cross-poll rounds exhausted |
| Report | ✅ COMPLETE |
Summary
PR #34383 fixes iOS scroll jitter in CollectionView when items contain Label.TextType="Html". The root cause is that HTML text updates are always async-dispatched, causing CV2 cells to size incorrectly on first measurement and re-layout after the async callback fires. The PR's fix is architecturally correct but has two quality concerns that should be addressed before merging.
Selected Fix: Attempt 2 (reversed conditional — detect CV1 for async, sync everywhere else) is preferred over the PR's approach.
Root Cause
LabelExtensions.UpdateText was written to dispatch UpdateTextHtml asynchronously to avoid an NSInternalInconsistencyException crash in CV1 (CarouselView handler v1) layouts. CV1 called UpdateText during its layout pass, and the synchronous AttributedText assignment caused a re-entrant layout crash. CV2 does not have this crash, but inherited the same async path — causing a two-pass layout (measure before HTML → measure again after HTML) that produces visible scroll jitter.
Fix Quality
Concern 1 — Architectural coupling (Priority: High)
The PR adds using Microsoft.Maui.Controls.Handlers.Items2; to LabelExtensions.cs, which lives in the Microsoft.Maui.Controls.Platform namespace. This introduces a direct dependency from platform-level extension code into a specific handler implementation namespace. While both are in the same assembly (Microsoft.Maui.Controls), this is a layering violation: platform helpers should not depend on handler internals.
Better approach (Attempt 2): Reverse the conditional — detect CV1 cells (ItemsViewCell from Handlers.Items) for async, and make sync the default everywhere else. This is architecturally cleaner because: (a) async is the exception (deprecated CV1 path), not the rule; (b) if any Items namespace must be imported, using the deprecated-path Items namespace is more justifiable than using the current-path Items2 namespace in low-level platform code; (c) sync-by-default reduces latency for all non-CV1 scenarios.
// Reverse conditional: only async for CV1, sync everywhere else
- if (IsPlatformLabelInsideCV2Cell(platformLabel))
+ if (!IsPlatformLabelInsideCV1Cell(platformLabel))
{
// Synchronous: safe outside CV1
platformLabel.UpdateTextHtml(text);
...
}
else
{
// Async: only for deprecated CV1 to avoid crash
DispatchQueue.MainQueue.DispatchAsync(() => { ... });
}Concern 2 — Double MapFormatting in CV2 sync path (Priority: Medium)
In the PR's CV2 synchronous branch, LabelExtensions.UpdateText calls Label.MapFormatting(labelHandlerSync, label). However, Label.MapText in Label.iOS.cs (which calls UpdateText) also calls MapFormatting(handler, label) immediately afterward. For HTML labels in CV2, MapFormatting runs twice per text update — wasted work and potentially extra layout passes.
The author argues removing it causes NSInternalInconsistencyException during fast scroll cell reuse. If that's true, something is off in the call sequence: MapText → UpdateText → MapFormatting → (return to MapText) → MapFormatting again. The correct fix is to understand why MapFormatting must be called from inside UpdateText rather than relying on MapText's call. Any alternative approach (Attempts 1, 2, 4, 5) avoids this issue because they don't add a second MapFormatting call inside UpdateText.
Concern 3 — No tests (Priority: Medium)
Gate was skipped — no tests exist. The author justifies this as untestable without live device scrolling. While the exact visual jitter cannot be automated, a device test or UI test verifying that a CollectionView with HTML labels loads without crash on iOS would add meaningful regression coverage. The write-tests-agent could create at least a smoke test.
Concern 4 — IsPlatformLabelInsideCV2Cell superview traversal cost (Priority: Low)
The helper walks the entire UIKit superview chain on every HTML text update. For deeply nested views this is called repeatedly during fast scrolling. A cached approach (or the Attempt 2 approach that avoids traversal entirely in the common path) would be more efficient.
Suggested Changes
- Replace the CV2 superview walk approach with the reversed conditional (detect CV1 for async, sync everywhere else). This removes the
Items2namespace dependency and makes sync the default. - Investigate why
MapFormattingmust be called insideUpdateTextfor the CV2 sync path (or confirm the double call is harmless). If it causes extra layout, remove it fromUpdateTextand rely onMapText's existing call. - Add tests — at minimum a device test that loads a CollectionView with HTML labels on iOS without crash.
Concern 1 — Architectural coupling: I have already checked this. Removing the MapFormatting call causes an NSInternalInconsistencyException during fast scrolling. Better approach (Attempt 2): Concern 2 — Double MapFormatting in CV2 sync path: I have already checked this. Removing the MapFormatting call causes an NSInternalInconsistencyException during fast scrolling. Concern 3 — No tests (Priority: Medium): This has already been checked. It requires a live device with a scrolling CollectionView and visual verification (manual observation or screenshot comparison). |
kubaflo
left a comment
There was a problem hiding this comment.
It will probably cause regression here: #26153. Otherwise if the crash doesn't happen we should remove the IsPlatformLabelInsideCV2Cell. Could you please verify if this change doesn't regress what has been fixed by the linked PR?
@kubaflo I have checked the test from PR #26153 and it did not fail with my fix. The IsPlatformLabelInsideCV2Cell check needs to stay — if I remove it, issue #33065 won't be fixed. This guard is what keeps both fixes working: CV1 still uses async (no crash), CV2 uses sync (no jitter). |
Code Review — PR #34383Independent AssessmentWhat this changes: On iOS, splits the
Also adds a Inferred motivation: The async dispatch was added by PR #26153 to avoid a crash when Reconciliation with PR NarrativeAuthor claims: HTML text jitter in CV2 CollectionView caused by async dispatch. Fix: apply synchronously in CV2, keep async for CV1. Agreement: Root cause analysis is correct. The async dispatch was a workaround for a CV1-specific crash (#25946). CV2 doesn't have this crash, so synchronous application is safe there. Findings
|
|
/azp run maui-pr-uitests , maui-pr-devicetests |
|
Azure Pipelines successfully started running 2 pipeline(s). |
…4383) <!-- 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! <!-- !!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING MAIN. !!!!!!! --> ### Root Cause: HTML text is applied asynchronously in .NET MAUI on iOS, causing the CollectionView cell to render first and then re-measure after the HTML is applied, which leads to visible resizing (scroll jitter). ### Description of Change Improvements to HTML text handling in CollectionView: * Updated `UpdateText` method in `LabelExtensions.cs` to check if the `UILabel` is inside a CV2 cell using the new `IsPlatformLabelInsideCV2Cell` method, allowing synchronous HTML text updates when safe and avoiding unnecessary layout passes. * Added the `IsPlatformLabelInsideCV2Cell` helper method to walk the UIKit superview chain and detect CV2 cells, improving reliability and preventing crashes in CV1 layouts. * Added a reference to `Microsoft.Maui.Controls.Handlers.Items2` to support the new CV2 cell detection logic. <!-- Enter description of the fix in this section --> ### Why Tests were not added: This bug occurs only during live scrolling of CollectionView cells on iOS when a Label with TextType="Html" is rendered. The issue depends on the precise timing of asynchronous HTML text application, which triggers a second layout pass while cells are visible, causing scroll jitter. Automated tests cannot reliably reproduce this because no framework can simulate real-time scrolling and layout timing at the native speed ### Issues Fixed <!-- Please make sure that there is a bug logged for the issue being fixed. The bug should describe the problem and how to reproduce it. --> Fixes #33065 ### Tested the behavior in the following platforms - [x] Windows - [x] Android - [x] iOS - [x] Mac | Before Issue Fix | After Issue Fix | |----------|----------| | <video src="https://github.com/user-attachments/assets/1045cbe3-e869-4e08-9562-8032dd9cea88"> | <video src="https://github.com/user-attachments/assets/0c7b3bbb-4917-482f-ac7e-05e343de3ae0"> | <!-- Are you targeting main? All PRs should target the main branch unless otherwise noted. -->
…tnet#34383) <!-- 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! <!-- !!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING MAIN. !!!!!!! --> ### Root Cause: HTML text is applied asynchronously in .NET MAUI on iOS, causing the CollectionView cell to render first and then re-measure after the HTML is applied, which leads to visible resizing (scroll jitter). ### Description of Change Improvements to HTML text handling in CollectionView: * Updated `UpdateText` method in `LabelExtensions.cs` to check if the `UILabel` is inside a CV2 cell using the new `IsPlatformLabelInsideCV2Cell` method, allowing synchronous HTML text updates when safe and avoiding unnecessary layout passes. * Added the `IsPlatformLabelInsideCV2Cell` helper method to walk the UIKit superview chain and detect CV2 cells, improving reliability and preventing crashes in CV1 layouts. * Added a reference to `Microsoft.Maui.Controls.Handlers.Items2` to support the new CV2 cell detection logic. <!-- Enter description of the fix in this section --> ### Why Tests were not added: This bug occurs only during live scrolling of CollectionView cells on iOS when a Label with TextType="Html" is rendered. The issue depends on the precise timing of asynchronous HTML text application, which triggers a second layout pass while cells are visible, causing scroll jitter. Automated tests cannot reliably reproduce this because no framework can simulate real-time scrolling and layout timing at the native speed ### Issues Fixed <!-- Please make sure that there is a bug logged for the issue being fixed. The bug should describe the problem and how to reproduce it. --> Fixes dotnet#33065 ### Tested the behavior in the following platforms - [x] Windows - [x] Android - [x] iOS - [x] Mac | Before Issue Fix | After Issue Fix | |----------|----------| | <video src="https://github.com/user-attachments/assets/1045cbe3-e869-4e08-9562-8032dd9cea88"> | <video src="https://github.com/user-attachments/assets/0c7b3bbb-4917-482f-ac7e-05e343de3ae0"> | <!-- Are you targeting main? All PRs should target the main branch unless otherwise noted. -->
…4383) <!-- 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! <!-- !!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING MAIN. !!!!!!! --> ### Root Cause: HTML text is applied asynchronously in .NET MAUI on iOS, causing the CollectionView cell to render first and then re-measure after the HTML is applied, which leads to visible resizing (scroll jitter). ### Description of Change Improvements to HTML text handling in CollectionView: * Updated `UpdateText` method in `LabelExtensions.cs` to check if the `UILabel` is inside a CV2 cell using the new `IsPlatformLabelInsideCV2Cell` method, allowing synchronous HTML text updates when safe and avoiding unnecessary layout passes. * Added the `IsPlatformLabelInsideCV2Cell` helper method to walk the UIKit superview chain and detect CV2 cells, improving reliability and preventing crashes in CV1 layouts. * Added a reference to `Microsoft.Maui.Controls.Handlers.Items2` to support the new CV2 cell detection logic. <!-- Enter description of the fix in this section --> ### Why Tests were not added: This bug occurs only during live scrolling of CollectionView cells on iOS when a Label with TextType="Html" is rendered. The issue depends on the precise timing of asynchronous HTML text application, which triggers a second layout pass while cells are visible, causing scroll jitter. Automated tests cannot reliably reproduce this because no framework can simulate real-time scrolling and layout timing at the native speed ### Issues Fixed <!-- Please make sure that there is a bug logged for the issue being fixed. The bug should describe the problem and how to reproduce it. --> Fixes #33065 ### Tested the behavior in the following platforms - [x] Windows - [x] Android - [x] iOS - [x] Mac | Before Issue Fix | After Issue Fix | |----------|----------| | <video src="https://github.com/user-attachments/assets/1045cbe3-e869-4e08-9562-8032dd9cea88"> | <video src="https://github.com/user-attachments/assets/0c7b3bbb-4917-482f-ac7e-05e343de3ae0"> | <!-- Are you targeting main? All PRs should target the main branch unless otherwise noted. -->
…4383) <!-- 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! <!-- !!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING MAIN. !!!!!!! --> ### Root Cause: HTML text is applied asynchronously in .NET MAUI on iOS, causing the CollectionView cell to render first and then re-measure after the HTML is applied, which leads to visible resizing (scroll jitter). ### Description of Change Improvements to HTML text handling in CollectionView: * Updated `UpdateText` method in `LabelExtensions.cs` to check if the `UILabel` is inside a CV2 cell using the new `IsPlatformLabelInsideCV2Cell` method, allowing synchronous HTML text updates when safe and avoiding unnecessary layout passes. * Added the `IsPlatformLabelInsideCV2Cell` helper method to walk the UIKit superview chain and detect CV2 cells, improving reliability and preventing crashes in CV1 layouts. * Added a reference to `Microsoft.Maui.Controls.Handlers.Items2` to support the new CV2 cell detection logic. <!-- Enter description of the fix in this section --> ### Why Tests were not added: This bug occurs only during live scrolling of CollectionView cells on iOS when a Label with TextType="Html" is rendered. The issue depends on the precise timing of asynchronous HTML text application, which triggers a second layout pass while cells are visible, causing scroll jitter. Automated tests cannot reliably reproduce this because no framework can simulate real-time scrolling and layout timing at the native speed ### Issues Fixed <!-- Please make sure that there is a bug logged for the issue being fixed. The bug should describe the problem and how to reproduce it. --> Fixes #33065 ### Tested the behavior in the following platforms - [x] Windows - [x] Android - [x] iOS - [x] Mac | Before Issue Fix | After Issue Fix | |----------|----------| | <video src="https://github.com/user-attachments/assets/1045cbe3-e869-4e08-9562-8032dd9cea88"> | <video src="https://github.com/user-attachments/assets/0c7b3bbb-4917-482f-ac7e-05e343de3ae0"> | <!-- Are you targeting main? All PRs should target the main branch unless otherwise noted. -->
…4383) <!-- 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! <!-- !!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING MAIN. !!!!!!! --> ### Root Cause: HTML text is applied asynchronously in .NET MAUI on iOS, causing the CollectionView cell to render first and then re-measure after the HTML is applied, which leads to visible resizing (scroll jitter). ### Description of Change Improvements to HTML text handling in CollectionView: * Updated `UpdateText` method in `LabelExtensions.cs` to check if the `UILabel` is inside a CV2 cell using the new `IsPlatformLabelInsideCV2Cell` method, allowing synchronous HTML text updates when safe and avoiding unnecessary layout passes. * Added the `IsPlatformLabelInsideCV2Cell` helper method to walk the UIKit superview chain and detect CV2 cells, improving reliability and preventing crashes in CV1 layouts. * Added a reference to `Microsoft.Maui.Controls.Handlers.Items2` to support the new CV2 cell detection logic. <!-- Enter description of the fix in this section --> ### Why Tests were not added: This bug occurs only during live scrolling of CollectionView cells on iOS when a Label with TextType="Html" is rendered. The issue depends on the precise timing of asynchronous HTML text application, which triggers a second layout pass while cells are visible, causing scroll jitter. Automated tests cannot reliably reproduce this because no framework can simulate real-time scrolling and layout timing at the native speed ### Issues Fixed <!-- Please make sure that there is a bug logged for the issue being fixed. The bug should describe the problem and how to reproduce it. --> Fixes #33065 ### Tested the behavior in the following platforms - [x] Windows - [x] Android - [x] iOS - [x] Mac | Before Issue Fix | After Issue Fix | |----------|----------| | <video src="https://github.com/user-attachments/assets/1045cbe3-e869-4e08-9562-8032dd9cea88"> | <video src="https://github.com/user-attachments/assets/0c7b3bbb-4917-482f-ac7e-05e343de3ae0"> | <!-- Are you targeting main? All PRs should target the main branch unless otherwise noted. -->
…4383) <!-- 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! <!-- !!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING MAIN. !!!!!!! --> ### Root Cause: HTML text is applied asynchronously in .NET MAUI on iOS, causing the CollectionView cell to render first and then re-measure after the HTML is applied, which leads to visible resizing (scroll jitter). ### Description of Change Improvements to HTML text handling in CollectionView: * Updated `UpdateText` method in `LabelExtensions.cs` to check if the `UILabel` is inside a CV2 cell using the new `IsPlatformLabelInsideCV2Cell` method, allowing synchronous HTML text updates when safe and avoiding unnecessary layout passes. * Added the `IsPlatformLabelInsideCV2Cell` helper method to walk the UIKit superview chain and detect CV2 cells, improving reliability and preventing crashes in CV1 layouts. * Added a reference to `Microsoft.Maui.Controls.Handlers.Items2` to support the new CV2 cell detection logic. <!-- Enter description of the fix in this section --> ### Why Tests were not added: This bug occurs only during live scrolling of CollectionView cells on iOS when a Label with TextType="Html" is rendered. The issue depends on the precise timing of asynchronous HTML text application, which triggers a second layout pass while cells are visible, causing scroll jitter. Automated tests cannot reliably reproduce this because no framework can simulate real-time scrolling and layout timing at the native speed ### Issues Fixed <!-- Please make sure that there is a bug logged for the issue being fixed. The bug should describe the problem and how to reproduce it. --> Fixes #33065 ### Tested the behavior in the following platforms - [x] Windows - [x] Android - [x] iOS - [x] Mac | Before Issue Fix | After Issue Fix | |----------|----------| | <video src="https://github.com/user-attachments/assets/1045cbe3-e869-4e08-9562-8032dd9cea88"> | <video src="https://github.com/user-attachments/assets/0c7b3bbb-4917-482f-ac7e-05e343de3ae0"> | <!-- Are you targeting main? All PRs should target the main branch unless otherwise noted. -->
…abels (#35341) <!-- Please keep the note below for people who 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 whether this change resolves your issue. Thank you! <!-- !!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING MAIN. !!!!!!! --> This PR reverts the changes introduced by #34383, which caused an NSInternalInconsistencyException during fast scrolling when a Label has TextType="HTML" inside a CV2 CollectionView on iOS. ### Root Cause of the Regression PR #34383 applied NSAttributedString HTML initialization synchronously inside cellForItemAtIndexPath. Per Apple's documentation, NSAttributedString HTML init uses WebKit internally, which pumps the CFRunLoop even on the main thread. This causes UIKit re-entrancy during UICollectionView's data source call, resulting in NSInternalInconsistencyException. ### Description of Change **iOS Label HTML Text Handling Simplification:** * Removed conditional logic that checked whether a `UILabel` was inside a CV2 (CollectionView/CarouselView v2) cell, and always dispatches HTML text updates asynchronously to the main queue to prevent crashes. * Deleted the helper method `IsPlatformLabelInsideCV2Cell` and its associated code, further simplifying the update logic. * Cleaned up unused imports by removing the reference to `Microsoft.Maui.Controls.Handlers.Items2`. <!-- Enter description of the fix in this section --> ### Issues Fixed <!-- Please make sure that there is a bug logged for the issue being fixed. The bug should describe the problem and how to reproduce it. --> Regression introduced by PR #34383 ### Failure test case: - AppShouldNotCrash <!-- Are you targeting main? All PRs should target the main branch unless otherwise noted. -->

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:
HTML text is applied asynchronously in .NET MAUI on iOS, causing the CollectionView cell to render first and then re-measure after the HTML is applied, which leads to visible resizing (scroll jitter).
Description of Change
Improvements to HTML text handling in CollectionView:
UpdateTextmethod inLabelExtensions.csto check if theUILabelis inside a CV2 cell using the newIsPlatformLabelInsideCV2Cellmethod, allowing synchronous HTML text updates when safe and avoiding unnecessary layout passes.IsPlatformLabelInsideCV2Cellhelper method to walk the UIKit superview chain and detect CV2 cells, improving reliability and preventing crashes in CV1 layouts.Microsoft.Maui.Controls.Handlers.Items2to support the new CV2 cell detection logic.Why Tests were not added:
This bug occurs only during live scrolling of CollectionView cells on iOS when a Label with TextType="Html" is rendered. The issue depends on the precise timing of asynchronous HTML text application, which triggers a second layout pass while cells are visible, causing scroll jitter. Automated tests cannot reliably reproduce this because no framework can simulate real-time scrolling and layout timing at the native speed
Issues Fixed
Fixes #33065
Tested the behavior in the following platforms
BeforeFix.mp4
AfterFix.mp4