Skip to content

[Android] Fix CollectionView LinearItemsLayout first/last items clipped when ItemSpacing changes at runtime#34664

Open
Shalini-Ashokan wants to merge 4 commits intodotnet:inflight/candidatefrom
Shalini-Ashokan:fix_34636
Open

[Android] Fix CollectionView LinearItemsLayout first/last items clipped when ItemSpacing changes at runtime#34664
Shalini-Ashokan wants to merge 4 commits intodotnet:inflight/candidatefrom
Shalini-Ashokan:fix_34636

Conversation

@Shalini-Ashokan
Copy link
Contributor

@Shalini-Ashokan Shalini-Ashokan commented Mar 26, 2026

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!

Issue Details

CollectionView with LinearItemsLayout, the first and last items become truncated/clipped after changing the ItemSpacing value at runtime. This affects both vertical and horizontal list orientations on Android.

Note: This is inflight/candate branch changes where exsiting PR #27093 causes the regression on this branch. So added this new fix to overcome the regression.

Root Cause

PR #27093 changed SpacingItemDecoration.GetItemOffsets to zero out the outer edge offsets (outRect.Top = 0 for item 0, outRect.Bottom = 0 for last item) for all layout types including LinearItemsLayout. However, MauiRecyclerView.UpdateItemSpacing still applied negative padding (SetPadding(-offset, ...)) on the RecyclerView for linear layouts. This conflict caused the first and last items to be pulled outside the visible area and clipped, since the positive offset that was supposed to cancel the negative padding was removed.

Description of Change

Added a _removeOuterEdgeSpacing boolean flag to SpacingItemDecoration, set to true only for GridItemsLayout. In GetItemOffsets, an early return is added when _removeOuterEdgeSpacing is false, skipping the edge-zeroing logic for LinearItemsLayout. This restores the correct balanced behavior for linear lists: the positive outRect offset (+N) and the negative RecyclerView padding (-N) cancel each other out at the edges, keeping the first and last items correctly positioned at the screen boundary.

Validated the behavior in the following platforms

  • Android
  • Windows
  • iOS
  • Mac

Issues Fixed

Fixes #34636

Output ScreenShot

Before After
BeforeFix AfterFix

@dotnet-policy-service dotnet-policy-service bot added the community ✨ Community Contribution label Mar 26, 2026
@dotnet-policy-service
Copy link
Contributor

Hey there @@Shalini-Ashokan! Thank you so much for your PR! Someone from the team will get assigned to your PR shortly and we'll get it reviewed.

@dotnet-policy-service dotnet-policy-service bot added the partner/syncfusion Issues / PR's with Syncfusion collaboration label Mar 26, 2026
@sheiksyedm sheiksyedm added platform/android area-controls-collectionview CollectionView, CarouselView, IndicatorView labels Mar 26, 2026
@sheiksyedm sheiksyedm marked this pull request as ready for review March 26, 2026 08:36
@sheiksyedm sheiksyedm added this to the .NET 10 SR6 milestone Mar 26, 2026
@sheiksyedm
Copy link
Contributor

/azp run maui-pr-uitests

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@dotnet dotnet deleted a comment from azure-pipelines bot Mar 26, 2026
@sheiksyedm
Copy link
Contributor

/azp run maui-pr-uitests

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@sheiksyedm
Copy link
Contributor

/azp run maui-pr-uitests

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@MauiBot
Copy link
Collaborator

MauiBot commented Mar 27, 2026

🚦 Gate — Test Verification

📊 Expand Full Gated93bff6 · Modified the test case to resolve the ios scrolling issue

Gate Result: ❌ FAILED

Platform: android


@MauiBot
Copy link
Collaborator

MauiBot commented Mar 27, 2026

🤖 AI Summary

📊 Expand Full Reviewd93bff6 · Modified the test case to resolve the ios scrolling issue
🔍 Pre-Flight — Context & Validation

Issue: #34636 - [MAUI] I2_Spacing_ItemSpacing - First and last item on the list is truncated after changing Spacing value.
PR: #34664 - [Android] Fix CollectionView LinearItemsLayout first/last items clipped when ItemSpacing changes at runtime
Platforms Affected: Android (primary), validated on Windows/iOS/Mac
Files Changed: 1 implementation, 2 test files + 2 snapshot PNGs

Key Findings

  • Regression introduced by PR [Android] CollectionView: Fix item spacing applied on outer edges causing scroll/rendering issues #27093 on inflight/candate branch — SpacingItemDecoration.GetItemOffsets was changed to zero out outer-edge offsets for ALL layout types (including LinearItemsLayout)
  • MauiRecyclerView.UpdateItemSpacing applies negative padding SetPadding(-offset, ...) for LinearItemsLayout to cancel the positive outer-edge offset — when PR [Android] CollectionView: Fix item spacing applied on outer edges causing scroll/rendering issues #27093 removed the positive offset but kept the negative padding, first/last items were pulled outside the visible area
  • Fix adds _removeOuterEdgeSpacing boolean flag (set true only for GridItemsLayout); linear layouts return early from GetItemOffsets without zeroing edges, restoring the balanced positive-offset + negative-padding behavior
  • Test uses VerifyScreenshot() without retryTimeout, which may cause flakiness after CollectionView layout update
  • Gate ❌ FAILED on Android — screenshot test did not pass as expected
  • Issue confirmed non-reproducible on main branch; only affects inflight/candate branch

Fix Candidates

# Source Approach Test Result Files Changed Notes
PR PR #34664 Add _removeOuterEdgeSpacing flag; skip edge-zeroing for LinearItemsLayout via early return ❌ Gate FAILED SpacingItemDecoration.cs Gate failed on Android screenshot test

🔧 Fix — Analysis & Comparison

Fix Candidates

# Source Approach Test Result Files Changed Notes
PR PR #34664 _removeOuterEdgeSpacing flag in SpacingItemDecoration; early return for Linear; keeps negative RecyclerView padding ❌ Gate FAILED 1 fix file Gate failed — screenshot mismatch or timing
1 Attempt 1 (claude-opus-4.6) Edge-zeroing applied to ALL layouts (Grid + Linear) + remove negative padding entirely from MauiRecyclerView ✅ PASS 2 files Simpler — no flag, no branching
2 Attempt 2 (claude-sonnet-4.6) Direct per-side ternary assignment (top = row==0?0:V) for all layouts, remove negative padding ✅ PASS 2 files Clean single-pass, no conditionals
3 Attempt 3 (gpt-5.3-codex) Only remove negative padding from MauiRecyclerView for LinearItemsLayout ❌ BLOCKED 1 file Unrelated CS0246 build error
4 Attempt 4 (gpt-5.4) Only remove negative padding from MauiRecyclerView for LinearItemsLayout (minimal) ❌ BLOCKED 1 file Same CS0246 build error

Cross-Pollination

Model Round New Ideas? Details
claude-opus-4.6 2 No NO NEW IDEAS
claude-sonnet-4.6 2 Yes Position-aware edge suppression for Linear only — effectively covered by Attempt 2
gpt-5.3-codex 2 Yes RecyclerView ClipToPadding=false strategy — significant refactor, too invasive for a regression fix

Exhausted: Yes
Selected Fix: Attempt 1 (claude-opus-4.6) — Apply edge-zeroing to ALL layouts in SpacingItemDecoration + remove negative padding from MauiRecyclerView.

Reason over PR's fix: Attempt 1 is a cleaner, more uniform solution. The PR's fix adds a conditional boolean flag that perpetuates the two-mechanism design (negative padding + selective edge-zeroing). Attempt 1 removes the dual-mechanism entirely, handling outer-edge spacing in one consistent place. Gate failed for PR's fix — attempts 1 and 2 both passed the same screenshot test.


📋 Report — Final Recommendation

⚠️ Final Recommendation: REQUEST CHANGES

Phase Status

Phase Status Notes
Pre-Flight ✅ COMPLETE Issue #34636 identified, regression from PR #27093
Gate ❌ FAILED Android screenshot test failed
Try-Fix ✅ COMPLETE 4 attempts: 2 passing, 2 blocked (env build error)
Report ✅ COMPLETE

Summary

PR #34664 fixes a regression (from PR #27093 on the inflight/candate branch) where CollectionView LinearItemsLayout first/last items become clipped after changing ItemSpacing at runtime. The root cause is a double-compensation conflict: PR #27093 zeroed outer-edge offsets for all layouts in SpacingItemDecoration.GetItemOffsets, while MauiRecyclerView.UpdateItemSpacing still applies negative RecyclerView padding for linear layouts. This combination pulls first/last items outside the clip boundary.

The gate failed on Android, and two independent alternative fixes (Attempts 1 and 2) both passed the same screenshot test, suggesting the PR's specific approach produces a subtly different rendering from what the committed snapshot captures.

Root Cause

MauiRecyclerView.UpdateItemSpacing applies SetPadding(-offset, -offset, -offset, -offset) for LinearItemsLayout, relying on SpacingItemDecoration.GetItemOffsets to add a matching positive offset at the outer edges to cancel the negative padding. PR #27093 removed the positive outer-edge offset (zeroing it) but left the negative padding intact, causing the net outer offset for first/last items to be negative — pulling them outside the visible area.

Fix Quality

PR's Fix Issues:

  1. Gate Failed — The screenshot test did not pass with the PR's changes on the gate's Android device, even though a snapshot was committed
  2. Perpetuates dual-mechanism design — The fix keeps the negative RecyclerView padding for LinearItemsLayout, which must now be carefully kept in sync with the _removeOuterEdgeSpacing flag in SpacingItemDecoration
  3. Test robustnessVerifyScreenshot() called without retryTimeout after a spacing change that triggers CollectionView re-layout; this can cause flaky failures if layout hasn't settled before the screenshot
  4. Snapshot quality — No retryTimeout in the test suggests the snapshot may have been captured before the animation/layout completed

Better Alternative Found:
Attempt 1 (claude-opus-4.6) passed the same test with a cleaner, symmetric approach:

  • Apply edge-zeroing to ALL layout types (not just Grid) in SpacingItemDecoration.GetItemOffsets
  • Remove negative padding from MauiRecyclerView.UpdateItemSpacing entirely (SetPadding(0, 0, 0, 0) always)
  • This eliminates the dual-mechanism entirely — outer-edge spacing handled in one place with no conditional branching

Suggested Changes:

  1. SpacingItemDecoration.cs: Remove the _removeOuterEdgeSpacing flag; keep GetItemOffsets edge-zeroing for all layout types (the existing logic already works for Linear with span=1)

  2. MauiRecyclerView.cs: Remove conditional negative padding; always use SetPadding(0, 0, 0, 0)

  3. Issue34636.cs (test): Add retryTimeout to VerifyScreenshot() to prevent flaky failures after layout:

    VerifyScreenshot(retryTimeout: TimeSpan.FromSeconds(2));
  4. Snapshot: Regenerate the Android snapshot with the updated test.


@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 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-controls-collectionview CollectionView, CarouselView, IndicatorView community ✨ Community Contribution partner/syncfusion Issues / PR's with Syncfusion collaboration platform/android 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.

4 participants