Skip to content

[iOS] Fixed CollectionView Scroll Jitter for TextType HTML Labels#34383

Merged
kubaflo merged 3 commits into
dotnet:inflight/currentfrom
SubhikshaSf4851:Fix-33065
Apr 13, 2026
Merged

[iOS] Fixed CollectionView Scroll Jitter for TextType HTML Labels#34383
kubaflo merged 3 commits into
dotnet:inflight/currentfrom
SubhikshaSf4851:Fix-33065

Conversation

@SubhikshaSf4851
Copy link
Copy Markdown
Contributor

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:

  • 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.

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

  • Windows
  • Android
  • iOS
  • Mac
Before Issue Fix After Issue Fix
BeforeFix.mp4
AfterFix.mp4

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Mar 9, 2026

🚀 Dogfood this PR with:

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

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

Or

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

@karthikraja-arumugam karthikraja-arumugam added platform/ios area-controls-collectionview CollectionView, CarouselView, IndicatorView labels Mar 9, 2026
@dotnet-policy-service dotnet-policy-service Bot added community ✨ Community Contribution partner/syncfusion Issues / PR's with Syncfusion collaboration labels Mar 9, 2026
@sheiksyedm sheiksyedm marked this pull request as ready for review March 24, 2026 07:20
Copilot AI review requested due to automatic review settings March 24, 2026 07:20
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR 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.UpdateText to apply HTML synchronously when the native UILabel is 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.

Comment thread src/Controls/src/Core/Platform/iOS/Extensions/LabelExtensions.cs
Comment thread src/Controls/src/Core/Platform/iOS/Extensions/LabelExtensions.cs Outdated
@MauiBot MauiBot added s/agent-changes-requested AI agent recommends changes - found a better alternative or issues s/agent-reviewed PR was reviewed by AI agent workflow (full 4-phase review) labels Mar 28, 2026
@SubhikshaSf4851
Copy link
Copy Markdown
Contributor Author

Concern 1: Remove the using Microsoft.Maui.Controls.Handlers.Items2 coupling

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.

Concern 2 : Resolve the double MapFormatting call

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

Concern 3 : Add a unit test

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.

@dotnet dotnet deleted a comment from MauiBot Apr 5, 2026
@dotnet dotnet deleted a comment from MauiBot Apr 5, 2026
@MauiBot
Copy link
Copy Markdown
Collaborator

MauiBot commented Apr 5, 2026

🚦 Gate - Test Before and After Fix

📊 Expand Full Gatee1fa826 · Updated suggestion

Gate Result: ⚠️ SKIPPED

No tests were detected in this PR.

Recommendation: Add tests to verify the fix using the write-tests-agent:

@copilot write tests for this PR

The agent will analyze the issue, determine the appropriate test type (UI test, device test, unit test, or XAML test), and create tests that verify the fix.


@MauiBot
Copy link
Copy Markdown
Collaborator

MauiBot commented Apr 5, 2026

🤖 AI Summary

📊 Expand Full Reviewe1fa826 · Updated suggestion
🔍 Pre-Flight — Context & Validation

Issue: #33065 - CollectionView scrolling is jittery when ItemTemplate contains Label with TextType="Html" in .NET 10
PR: #34383 - [iOS] Fixed CollectionView Scroll Jitter for TextType HTML Labels
Platforms Affected: iOS only
Files Changed: 1 implementation (LabelExtensions.cs), 0 test files

Key Findings

  • HTML text updates in iOS LabelExtensions.UpdateText are dispatched asynchronously to avoid a crash in CV1 (CarouselView handler v1). This async dispatch causes CV2 cells to render first and then re-measure after HTML is applied, producing visible scroll jitter.
  • PR fix: adds IsPlatformLabelInsideCV2Cell() helper that walks the UIKit superview chain to detect ItemsViewCell2. If inside CV2, applies HTML synchronously; otherwise uses the existing async dispatch path.
  • Architecture concern: LabelExtensions.cs (in Microsoft.Maui.Controls.Platform namespace) now using Microsoft.Maui.Controls.Handlers.Items2 — introduces a layering coupling from platform-level code to a handler-level class. Both are in the same assembly (Microsoft.Maui.Controls), so this is not an inter-assembly dependency, but it is a coupling of platform extension code to a specific handler implementation.
  • Double MapFormatting in CV2 path: In the PR's sync branch, LabelExtensions.UpdateText calls Label.MapFormatting(labelHandlerSync, label). But Label.MapText in Label.iOS.cs (the caller) also calls MapFormatting(handler, label) immediately after UpdateText returns. For HTML labels in CV2 this results in MapFormatting running twice per text update. Author argued removing it causes NSInternalInconsistencyException during fast scrolling.
  • Superview walk performance: IsPlatformLabelInsideCV2Cell traverses the entire UIKit superview chain on every HTML text update. For deep view hierarchies this could be a non-trivial cost called repeatedly per cell.
  • No tests added: Gate was SKIPPED. Author justifies that the bug only manifests during live device scrolling at native speed and cannot be reproduced by automated tests.
  • Prior copilot review flagged: (1) double MapFormatting, (2) comment typo. Comment typo was accepted; double MapFormatting was kept by author.

Fix Candidates

# 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 ⚠️ SKIPPED (Gate - no tests) 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 ⚠️ Gate SKIPPED 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 (uses Items for 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 UpdateTextHtml itself 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 ⚠️ SKIPPED 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: MapTextUpdateTextMapFormatting → (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

  1. Replace the CV2 superview walk approach with the reversed conditional (detect CV1 for async, sync everywhere else). This removes the Items2 namespace dependency and makes sync the default.
  2. Investigate why MapFormatting must be called inside UpdateText for the CV2 sync path (or confirm the double call is harmless). If it causes extra layout, remove it from UpdateText and rely on MapText's existing call.
  3. Add tests — at minimum a device test that loads a CollectionView with HTML labels on iOS without crash.

@SubhikshaSf4851
Copy link
Copy Markdown
Contributor Author

🤖 AI Summary

📊 Expand Full Reviewe1fa826 · Updated suggestion

Concern 1 — Architectural coupling:

I have already checked this. Removing the MapFormatting call causes an NSInternalInconsistencyException during fast scrolling.

Better approach (Attempt 2):
I also checked Attempt 2. After reversing the condition for CV1, the exception still occurs during fast scrolling.

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).

Copy link
Copy Markdown
Contributor

@kubaflo kubaflo left a comment

Choose a reason for hiding this comment

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

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?

@SubhikshaSf4851
Copy link
Copy Markdown
Contributor Author

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).
Screenshot 2026-04-13 at 12 09 59

@kubaflo
Copy link
Copy Markdown
Contributor

kubaflo commented Apr 13, 2026

Code Review — PR #34383

Independent Assessment

What this changes: On iOS, splits the TextType.Html path in LabelExtensions.UpdateText into two branches:

  1. CV2 path (synchronous): When the UILabel is inside an ItemsViewCell2 (determined by walking the superview chain), applies HTML text synchronously. No DispatchAsync, no InvalidateMeasure.
  2. CV1/general path (asynchronous): Original behavior — dispatches to main queue, applies HTML, re-applies formatting, and invalidates measure.

Also adds a IsPlatformLabelInsideCV2Cell helper that walks the UIView.Superview chain looking for ItemsViewCell2.

Inferred motivation: The async dispatch was added by PR #26153 to avoid a crash when NSAttributedString with HTML is called during a CV1 layout pass. But in CV2, this async dispatch causes a visible jitter — the cell renders with plain text first, then the HTML-formatted text pops in on the next frame, causing the scroll position to jump.

Reconciliation with PR Narrative

Author 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

⚠️ Warning — Superview walk creates architectural coupling between Controls-layer and Items2 handler

LabelExtensions.cs (in Controls.Core/Platform/iOS/Extensions/) now imports Microsoft.Maui.Controls.Handlers.Items2 to reference ItemsViewCell2. This creates a dependency from a general-purpose extension class to a specific handler implementation.

If ItemsViewCell2 is renamed, moved, or replaced, this code silently breaks (returns false, falls back to async path — functionally correct but jitter returns). This is a maintenance concern, not a correctness issue.

Alternative considered by author: Using GetType().Name string comparison — author says it didn't resolve the jitter. The direct type check is the pragmatic choice here.

⚠️ Warning — Double MapFormatting call in CV2 path

In the synchronous CV2 path:

  1. platformLabel.UpdateTextHtml(text) applies HTML → strips MAUI font/color styling
  2. Label.MapFormatting(labelHandlerSync, label) re-applies MAUI styling

But the caller Label.MapText (in Label.iOS.cs:22-27) calls UpdateText then MapFormatting again:

public static void MapText(ILabelHandler handler, Label label)
{
    Platform.LabelExtensions.UpdateText(handler.PlatformView, label);
    MapFormatting(handler, label);  // <-- second call
}

This means MapFormatting runs twice in the CV2 path. The author investigated removing the inner call but reports it causes NSInternalInconsistencyException during fast scrolling cell reuse. If true, keeping the double call is the safer choice — but it should have a comment explaining why it's necessary despite appearing redundant.

⚠️ Warning — No test

The author explains this is difficult to test because it depends on "real-time scrolling and layout timing at the native speed." kubaflo (maintainer) asked the author to verify no regression from PR #26153 — the author confirmed the existing #26153 test passes. However, there's no new test ensuring the synchronous path doesn't regress in the future. A device test that creates a CV2 with HTML labels and verifies the AttributedText is set synchronously (not after a dispatch) would catch a revert.

✅ Correct — CV1 crash path is preserved

The else branch keeps the original DispatchQueue.MainQueue.DispatchAsync path for all non-CV2 contexts (including CV1 CarouselView, standalone labels, etc.). This ensures PR #26153's crash fix is not regressed.

✅ Correct — Superview walk is safe and bounded

IsPlatformLabelInsideCV2Cell walks Superview up to the root. iOS view hierarchies are shallow (typically < 20 levels), so this is O(n) with small n. The check runs during cell layout — not a hot loop. No performance concern.

✅ Correct — InvalidateMeasure correctly skipped in CV2 path

In the async path, InvalidateMeasure is needed because text is applied outside the layout pass. In the CV2 synchronous path, text is applied during the layout pass, so the measure is already correct. Skipping it avoids the double-layout jitter.

CI Status

  • maui-pr: ✅ All stages pass
  • Build Analysis: ✅ Pass

Devil's Advocate

  1. Could the synchronous HTML path crash in CV2? The original crash (iOS App crashes on iOS 18 when placing html label in carousel view with > 2 elements #25946) was specifically about calling NSAttributedString init with HTML during a CV1 layout pass that triggers WebKit synchronization. CV2 uses a different layout mechanism (UICollectionViewCompositionalLayout vs CV1's custom layout), and the author + maintainer confirmed no crash. The explicit CV2 guard limits exposure.

  2. What about labels inside CV2 that are NOT in cell templates? (e.g., EmptyView, Header/Footer). IsPlatformLabelInsideCV2Cell checks for ItemsViewCell2 specifically — headers, footers, and empty views would fall through to the async path. This is correct/conservative.

  3. What if CV2's cell type changes in the future? If ItemsViewCell2 is refactored, the superview check silently fails and falls back to async. This is a safe failure mode — users get jitter again but no crash.

  4. Could this affect labels outside of CollectionView? No — standalone labels, labels in StackLayout, etc. never have ItemsViewCell2 in their superview chain. They always take the async path (unchanged behavior).

Verdict: LGTM with minor notes

Confidence: high

Summary: Pragmatic fix that correctly identifies the root cause (async HTML dispatch causing double-layout jitter in CV2) and applies a targeted workaround scoped to CV2 cells only. The CV1 crash-avoidance path is preserved. The architectural coupling and double MapFormatting call are trade-offs acknowledged by the author. No test is provided due to the timing-dependent nature of the bug, but the author confirmed no regression from #26153. CI is fully green.

@kubaflo
Copy link
Copy Markdown
Contributor

kubaflo commented Apr 13, 2026

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

@azure-pipelines
Copy link
Copy Markdown

Azure Pipelines successfully started running 2 pipeline(s).

@kubaflo kubaflo changed the base branch from main to inflight/current April 13, 2026 21:30
@kubaflo kubaflo merged commit cc88e6a into dotnet:inflight/current Apr 13, 2026
91 of 94 checks passed
PureWeen pushed a commit that referenced this pull request Apr 14, 2026
…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.
-->
devanathan-vaithiyanathan pushed a commit to Tamilarasan-Paranthaman/maui that referenced this pull request Apr 21, 2026
…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.
-->
PureWeen pushed a commit that referenced this pull request Apr 22, 2026
…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.
-->
PureWeen pushed a commit that referenced this pull request Apr 28, 2026
…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.
-->
PureWeen pushed a commit that referenced this pull request Apr 29, 2026
…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.
-->
github-actions Bot pushed a commit that referenced this pull request May 6, 2026
…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.
-->
kubaflo pushed a commit that referenced this pull request May 7, 2026
…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.
-->
@github-actions github-actions Bot locked and limited conversation to collaborators May 14, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-controls-collectionview CollectionView, CarouselView, IndicatorView collectionview-cv2 community ✨ Community Contribution partner/syncfusion Issues / PR's with Syncfusion collaboration platform/ios s/agent-changes-requested AI agent recommends changes - found a better alternative or issues s/agent-reviewed PR was reviewed by AI agent workflow (full 4-phase review)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

CollectionView scrolling is jittery when ItemTemplate contains Label with TextType="Html" in .NET 10

6 participants