Skip to content

[iOS] Fix incorrect FirstVisibleItemIndex reported by CollectionView.Scrolled after programmatic scroll#33719

Merged
kubaflo merged 7 commits intodotnet:inflight/currentfrom
Shalini-Ashokan:fix-33614
Mar 18, 2026
Merged

[iOS] Fix incorrect FirstVisibleItemIndex reported by CollectionView.Scrolled after programmatic scroll#33719
kubaflo merged 7 commits intodotnet:inflight/currentfrom
Shalini-Ashokan:fix-33614

Conversation

@Shalini-Ashokan
Copy link
Copy Markdown
Contributor

@Shalini-Ashokan Shalini-Ashokan commented Jan 27, 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

On iOS and MacCatalyst, the CollectionView.Scrolled event reports an incorrect FirstVisibleItemIndex after a programmatic ScrollTo() call. The reported index does not match the actual first visible item displayed on the screen.

Root Cause

The previous implementation used IndexPathsForVisibleItems.First() to determine the first visible item. On iOS/MacCatalyst, that collection can include prefetched cells outside the actual viewport, so the reported first visible index could be earlier than the item shown at the leading edge.

Description of Change

Updated the iOS CollectionView delegators to compute the first visible item from LayoutAttributesForElementsInRect(...) and select the first visible cell that intersects the current viewport. This avoids relying on prefetched cells when raising Scrolled.

Applied the fix to both:

ItemsViewDelegator.cs
ItemsViewDelegator2.cs

Validated the behavior in the following platforms

  • Android
  • Windows
  • iOS
  • Mac

Issues Fixed

Fixes #33614

Output ScreenShot

Before After
33614-BeforeFix.mov
33614-AfterFix.mov

@dotnet-policy-service dotnet-policy-service bot added community ✨ Community Contribution partner/syncfusion Issues / PR's with Syncfusion collaboration labels Jan 27, 2026
@sheiksyedm sheiksyedm marked this pull request as ready for review January 27, 2026 11:07
Copilot AI review requested due to automatic review settings January 27, 2026 11:07
@sheiksyedm sheiksyedm added platform/ios area-controls-collectionview CollectionView, CarouselView, IndicatorView labels Jan 27, 2026
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 fixes an issue where CollectionView.Scrolled event reports incorrect FirstVisibleItemIndex values on iOS and MacCatalyst after a programmatic ScrollTo() call. The root cause was that the previous implementation relied on IndexPathsForVisibleItems.First(), which includes prefetched cells that are not actually visible on screen.

Changes:

  • Replaced the direct use of IndexPathsForVisibleItems.First() with a new GetIndexPathAtPoint() method that uses IndexPathForItemAtPoint() to determine the actual first visible item
  • Applied the same logic for determining the center item index
  • Added UI tests to verify the fix works correctly

Reviewed changes

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

File Description
src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue33614.cs NUnit test that verifies FirstVisibleItemIndex is correct after programmatic scroll
src/Controls/tests/TestCases.HostApp/Issues/Issue33614.cs Test page demonstrating the issue with a CollectionView, button to trigger scroll, and label showing the index
src/Controls/src/Core/Handlers/Items2/iOS/ItemsViewDelegator2.cs Updated to use GetIndexPathAtPoint() method for both first and center item indices (active iOS/MacCatalyst handler)
src/Controls/src/Core/Handlers/Items/iOS/ItemsViewDelegator.cs Updated to use GetIndexPathAtPoint() method for both first and center item indices (deprecated iOS handler)

Comment on lines +17 to +20
App.WaitForElement("ScrollToButton");
App.Tap("ScrollToButton");
var firstIndexText = App.FindElement("FirstIndexLabel").GetText();
Assert.That(firstIndexText, Is.EqualTo("FirstVisibleItemIndex: 15"));
Copy link

Copilot AI Jan 27, 2026

Choose a reason for hiding this comment

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

The test may have a timing issue. After tapping the button, the test immediately reads the label text without waiting for the scroll animation to complete or for the label to update. This could lead to a race condition where the test reads the old value before the Scrolled event fires and updates the label.

Consider adding a wait or retry mechanism to ensure the label has been updated with the expected value. For example, you could use App.WaitForElement with a lambda that checks for the expected text, or add Task.Delay similar to other tests that wait for scroll animations (see Issue18961.cs line 29 which uses await Task.Delay(1000) after a scroll).

Copilot uses AI. Check for mistakes.

namespace Maui.Controls.Sample.Issues;

[Issue(IssueTracker.Github, 33614, "CollectionView Scrolled event reports incorrect FirstVisibleItemIndex after programmatic ScrollTo", PlatformAffected.iOS)]
Copy link

Copilot AI Jan 27, 2026

Choose a reason for hiding this comment

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

The PlatformAffected attribute should include macOS (MacCatalyst). According to the linked issue #33614, this bug affects both iOS and MacCatalyst. Since MacCatalyst uses the same iOS handlers (Items2/iOS), the fix applies to both platforms. The attribute should be updated to PlatformAffected.iOS | PlatformAffected.macOS.

Suggested change
[Issue(IssueTracker.Github, 33614, "CollectionView Scrolled event reports incorrect FirstVisibleItemIndex after programmatic ScrollTo", PlatformAffected.iOS)]
[Issue(IssueTracker.Github, 33614, "CollectionView Scrolled event reports incorrect FirstVisibleItemIndex after programmatic ScrollTo", PlatformAffected.iOS | PlatformAffected.macOS)]

Copilot uses AI. Check for mistakes.
@PureWeen
Copy link
Copy Markdown
Member

/rebase

@PureWeen
Copy link
Copy Markdown
Member

🔧 Try-Fix Continuation (Attempts 5-6)

Previous comment hit GitHub's 65536 character limit. Continuing with remaining attempts...


Fix Attempt 5: Leading-edge Proximity with AdjustedContentInset

Model: gpt-5.1-codex-max
Status: ✅ PASS

Approach: Uses AdjustedContentInset (modern iOS API that accounts for safe area) combined with proximity calculation to find the first truly visible item.

// Calculate visible area top edge using AdjustedContentInset
var visibleTop = collectionView.ContentOffset.Y + collectionView.AdjustedContentInset.Top;

// Find first item whose top edge is at or below visible area
foreach (var indexPath in indexPathsForVisibleItems)
{
    var attrs = collectionView.CollectionViewLayout.LayoutAttributesForItem(indexPath);
    if (attrs != null && attrs.Frame.Y >= visibleTop - 1) // 1pt tolerance
        return indexPath;
}

Key Advantages:

  • ✅ Uses AdjustedContentInset for accurate safe area handling
  • ✅ Proximity tolerance handles sub-pixel positioning
  • ✅ Works with modern iOS layout patterns

Fix Attempt 6: Binary Search + Layout Attributes

Model: claude-sonnet-4
Status: ✅ PASS

Approach: O(log n) binary search through IndexPathsForVisibleItems, querying layout system for each candidate.

static NSIndexPath GetFirstTrulyVisibleIndexPath(UICollectionView collectionView, List<NSIndexPath> items)
{
    var visibleTop = collectionView.ContentOffset.Y + collectionView.ContentInset.Top;
    int lo = 0, hi = items.Count - 1;
    NSIndexPath result = items[0];
    
    while (lo <= hi)
    {
        int mid = (lo + hi) / 2;
        var attrs = collectionView.CollectionViewLayout.LayoutAttributesForItem(items[mid]);
        if (attrs != null && attrs.Frame.Y >= visibleTop)
        {
            result = items[mid];
            hi = mid - 1; // Look for earlier item
        }
        else
        {
            lo = mid + 1;
        }
    }
    return result;
}

Key Advantages:

  • ✅ O(log n) complexity vs O(n) for iteration
  • ✅ Uses layout system as authority
  • ✅ Efficient for large collections

🏆 Model Consensus: Best Approach

Three models (opus, gpt-5.2-codex, gemini) evaluated all 7 approaches:

Approach Opus Rank GPT-5.2 Rank Gemini Rank Average
LayoutAttributesForElementsInRect 3rd 🥇 1st 🥇 1st 1.67
AdjustedContentInset 🥇 1st 5th 4th 3.33
IndexPath + LayoutAttributes 7th 🥈 2nd 🥈 2nd 3.67
VisibleCells Intersection 5th 🥉 3rd 🥉 3rd 3.67
Multi-point probe 4th 4th 5th 4.33
PR Fix (Original) 🥈 2nd 6th 6th 4.67
Binary search 6th 7th 7th 6.67

Recommendation

The current PR fix is acceptable for this issue:

  • ✅ Solves the reported bug
  • ✅ Verified: FAIL without fix → PASS with fix
  • ✅ Simple O(1) implementation

For future robustness (grid layouts, gaps, headers), LayoutAttributesForElementsInRect would be more comprehensive.

Copy link
Copy Markdown
Member

@PureWeen PureWeen left a comment

Choose a reason for hiding this comment

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

Can you evaluate the approaches recommended and see if this influences the approach here?

For example LayoutAttributesForElementsInRect appears to be a favorite!

@Shalini-Ashokan
Copy link
Copy Markdown
Contributor Author

Can you evaluate the approaches recommended and see if this influences the approach here?

For example LayoutAttributesForElementsInRect appears to be a favorite!

@PureWeen, I updated the fix to use LayoutAttributesForElementsInRect to find the first visible item index

@sheiksyedm
Copy link
Copy Markdown
Contributor

/rebase

@rmarinho rmarinho added s/agent-approved AI agent recommends approval - PR fix is correct and optimal s/agent-gate-passed AI verified tests catch the bug (fail without fix, pass with fix) s/agent-fix-lose Author adopted the agent's fix and it turned out to be bad s/agent-reviewed PR was reviewed by AI agent workflow (full 4-phase review) labels Feb 18, 2026
@kubaflo kubaflo added s/agent-fix-pr-picked AI could not beat the PR fix - PR is the best among all candidates and removed s/agent-fix-lose Author adopted the agent's fix and it turned out to be bad labels Feb 20, 2026
@kubaflo kubaflo added s/agent-review-incomplete AI agent could not complete all phases (blocker, timeout, error) and removed s/agent-approved AI agent recommends approval - PR fix is correct and optimal labels Mar 17, 2026
@dotnet dotnet deleted a comment from PureWeen Mar 18, 2026
@kubaflo
Copy link
Copy Markdown
Contributor

kubaflo commented Mar 18, 2026

🤖 AI Summary

📊 Expand Full Review858c4b0 · modified the fix
🔍 Pre-Flight — Context & Validation

Issue: #33614 - [iOS, Mac] CollectionView Scrolled event reports incorrect FirstVisibleItemIndex after programmatic ScrollTo
PR: #33719 - [iOS] Fix incorrect FirstVisibleItemIndex reported by CollectionView.Scrolled after programmatic scroll
Platforms Affected: iOS, MacCatalyst
Files Changed: 2 implementation, 2 test

Key Findings

  • The linked issue reports the bug on both iOS and MacCatalyst after ScrollTo(index, position: ScrollToPosition.Start, animate: true), with incorrect FirstVisibleItemIndex even after scrolling completes.
  • The PR updates both iOS handler implementations (Items/ and Items2/) to derive the first visible item from LayoutAttributesForElementsInRect, explicitly filtering to visible cells rather than trusting prefetched IndexPathsForVisibleItems ordering.
  • Added coverage is a UI test pair for issue 33614 (TestCases.HostApp + TestCases.Shared.Tests), so Gate should use the UI verification path on iOS.
  • Existing review feedback identified two remaining risks to validate: the UI test may be timing-sensitive after animated scrolling, and the HostApp issue page still declares only PlatformAffected.iOS even though the issue and handler change affect MacCatalyst too.
  • Prior review history exists on the PR, including a human request to evaluate LayoutAttributesForElementsInRect; the current patch appears to incorporate that direction, but the branch labels show the previous agent run was incomplete.

Edge Cases / Discussion Notes

  • The issue is validated on MAUI 9.x and 10.x and specifically calls out both iOS and Mac platform reproduction.
  • Because this uses animated programmatic scroll, correctness depends on final visible geometry rather than prefetched cell membership.
  • If the new UI test reads the label before the scroll animation finishes, Gate may expose a race rather than a handler bug.

File Classification

  • Implementation:
    • src/Controls/src/Core/Handlers/Items/iOS/ItemsViewDelegator.cs
    • src/Controls/src/Core/Handlers/Items2/iOS/ItemsViewDelegator2.cs
  • UI test HostApp page:
    • src/Controls/tests/TestCases.HostApp/Issues/Issue33614.cs
  • UI test NUnit implementation:
    • src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue33614.cs

Fix Candidates

# Source Approach Test Result Files Changed Notes
PR PR #33719 Replace IndexPathsForVisibleItems.First() with a layout-attribute scan over the actual visible rect to choose the first visible PENDING (Gate) ItemsViewDelegator.cs, ItemsViewDelegator2.cs, Issue33614.cs (HostApp/UI test pair) Current PR aligns with prior human feedback favoring LayoutAttributesForElementsInRect. cell.

🚦 Gate — Test Verification

Gate Result PASSED:

Platform: ios
Mode: Full Verification

  • Tests FAIL without fix:
  • Tests PASS with fix:

Notes

  • Verification ran through the repository verify-tests-fail-without-fix flow for Issue33614.
  • Decisive result: the UI test failed against the broken baseline and passed once the PR fix files were restored.
  • The verification agent reported successful build/deploy/test execution on iOS simulator, confirming the PR's test actually catches the issue it covers.

🔧 Fix — Analysis & Comparison

Fix Candidates

# Source Approach Test Result Files Changed Notes
1 try-fix (claude-opus-4.6) Point-query strategy using IndexPathForItemAtPoint, extra leading-edge probes, and fallback checks. PASS 2 files Valid alternative, but more fallback code than the PR fix.
2 try-fix (claude-sonnet-4.6) Walk sorted visible index paths and return the first item whose per-item layout attributes intersect the visible rect. PASS 2 files Simple and early-exit, but depends on visible index ordering.
3 try-fix (gpt-5.3-codex) Use UICollectionView.VisibleCells plus leading-edge geometry based on content offset and insets. PASS 2 files Uses rendered cells only, independent from attribute scans.
4 try-fix (gemini-3-pro-preview) Sort visible index paths and return the first item whose frame end crosses the viewport threshold using adjusted insets. PASS 2 files Geometry-based threshold strategy; more assumptions than the PR fix.
5 try-fix (cross-pollination) Cache first-visible state from WillDisplayCell and DidEndDisplayingCell instead of querying geometry at scroll time. FAIL 4 files Reproduced the bug because lifecycle callbacks lag the final Scrolled event.
PR PR #33719 Scan layout attributes for elements in the visible rect, filter to cells, and pick the earliest visible one. PASS (Gate) 4 files Original PR fix verified by gate.

Cross-Pollination

Model Round New Ideas? Details
claude-opus-4.6 2 No NO NEW IDEAS
claude-sonnet-4.6 2 Yes NEW IDEA: cache first-visible state from cell lifecycle callbacks and use that instead of geometry queries. Tested and failed.
gpt-5.3-codex 2 No NO NEW IDEAS
gemini-3-pro-preview 2 No NO NEW IDEAS

Exhausted: Yes
Selected Fix: PR - It is the most robust passing option because it queries current visible geometry directly, avoids ordering and lifecycle timing assumptions, and aligns with the prior human feedback favoring LayoutAttributesForElementsInRect.


📋 Report — Final Recommendation

Final Recommendation: APPROVE

Phase Status

Phase Status Notes
Pre-Flight COMPLETE Issue and PR context gathered, files classified, prior review feedback incorporated.
Gate PASSED iOS full verification confirmed FAIL without fix and PASS with fix for Issue33614.
Try-Fix COMPLETE 5 attempts total, 4 passing alternatives, 1 failing stateful cross-pollination idea.
Report COMPLETE

Summary

PR #33719 fixes the reported iOS and MacCatalyst CollectionView bug by replacing the naive use of IndexPathsForVisibleItems.First() with a visible-rect layout-attribute query. The gate verified that the added UI test actually catches the bug on iOS. Independent try-fix exploration found several other geometry-based solutions that also pass, but the PR's approach is the most robust of the passing options.

Root Cause

UIKit can include prefetched cells in IndexPathsForVisibleItems even when those cells are already outside the viewport after a programmatic ScrollTo animation. Using the first entry from that collection therefore reports a stale first visible item index. Any correct fix must derive the answer from the collection view's current visible geometry at the time the Scrolled event is raised.

Fix Quality

The PR fix directly interrogates the visible rect through LayoutAttributesForElementsInRect, filters to actual cells, and chooses the earliest visible item. Compared with the passing alternatives, it has the best tradeoff of correctness and robustness because it does not depend on visible-index ordering, hit-test probe fallbacks, or cell lifecycle timing. The extra stateful cross-pollination idea failed exactly because lifecycle bookkeeping lags the final Scrolled callback, which reinforces that the PR's geometry-at-query-time approach is the right class of solution.

Residual Notes

  • The added UI test passed in gate verification, although it still reads the label immediately after tapping the animated ScrollTo trigger; that is worth keeping an eye on if future flakiness appears.
  • The HostApp issue page still declares PlatformAffected.iOS even though the issue description and handler fix cover MacCatalyst too; this does not block approval for the iOS review requested here, but it is a follow-up worth considering.

📋 Expand PR Finalization Review

PR #33719 Finalization Review

Title

Current: [iOS] Fix incorrect FirstVisibleItemIndex reported by CollectionView.Scrolled after programmatic scroll

Assessment: Good as-is.

It is specific, searchable, and matches the implementation at a high level.

Description

Assessment: Needs update before merge.

The current body is no longer accurate:

  • It says the fix added a GetIndexPathAtPoint() method, but the actual implementation uses GetFirstVisibleIndexPathUsingLayoutAttributes(...) with LayoutAttributesForElementsInRect(...).
  • It says Android and Windows were validated, but the code changes are iOS/MacCatalyst-only and the PR does not include evidence for Android/Windows validation.
  • The issue and test coverage target both iOS and MacCatalyst, but the write-up does not clearly reflect the final platform scope.

Recommended direction: Keep the existing NOTE block and issue context, but update the Description of Change to describe the final layout-attributes-based approach and narrow the validation/platform wording to what was actually exercised.

A good replacement for the main body would be:

### Issue Details
On iOS and MacCatalyst, `CollectionView.Scrolled` could report an incorrect `FirstVisibleItemIndex` after a programmatic `ScrollTo(..., position: ScrollToPosition.Start, animate: true)`.

### Root Cause
The previous implementation used `IndexPathsForVisibleItems.First()` to determine the first visible item. On iOS/MacCatalyst, that collection can include prefetched cells outside the actual viewport, so the reported first visible index could be earlier than the item shown at the leading edge.

### Description of Change
Updated the iOS CollectionView delegators to compute the first visible item from `LayoutAttributesForElementsInRect(...)` and select the first visible cell that intersects the current viewport. This avoids relying on prefetched cells when raising `Scrolled`.

Applied the fix to both:
- `src/Controls/src/Core/Handlers/Items/iOS/ItemsViewDelegator.cs`
- `src/Controls/src/Core/Handlers/Items2/iOS/ItemsViewDelegator2.cs`

Added a HostApp repro page and UITest for issue #33614.

### Issues Fixed
Fixes #33614

Code Review Findings

Critical issues

1. UITest is race-prone after animated ScrollTo

  • File: src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue33614.cs
  • Problem: The test taps ScrollToButton and immediately reads FirstIndexLabel. Because the scroll is animated (animate: true), the label can still contain the old value when the assertion runs.
  • Why it matters: This can produce intermittent failures even if the handler fix is correct.
  • Recommendation: Wait for the expected post-scroll state before asserting, similar to other scrolling tests in this repo. For example, wait/retry until FirstIndexLabel becomes FirstVisibleItemIndex: 15, or use a deliberate async delay pattern if no better wait primitive is available.

2. Issue page metadata should include MacCatalyst

  • File: src/Controls/tests/TestCases.HostApp/Issues/Issue33614.cs
  • Problem: The page is marked with PlatformAffected.iOS, but issue [iOS, Mac] CollectionView Scrolled event reports incorrect FirstVisibleItemIndex after programmatic ScrollTo #33614 is explicitly filed for both iOS and macOS, and this PR updates both shared iOS handlers (Items/ and Items2/) used by MacCatalyst.
  • Why it matters: The test metadata understates the affected platform surface and makes the issue page harder to discover/run for MacCatalyst verification.
  • Recommendation: Update the attribute to include macOS/MacCatalyst, e.g. PlatformAffected.iOS | PlatformAffected.macOS.

Suggestions

  • Consider updating the PR description to mention that the final implementation followed the review feedback favoring LayoutAttributesForElementsInRect(...).
  • If the author wants to keep the platform prefix broad, the current title is acceptable; the more important fix is making the body accurate.

Looks good

  • The functional fix was applied to both iOS handler stacks: legacy Items/ and current Items2/, which keeps behavior aligned.
  • Using layout attributes to determine the first visible item is a better match for the reported prefetching problem than relying on IndexPathsForVisibleItems.First().
  • The PR includes a targeted HostApp repro page plus a UITest, which is the right validation shape for this bug.

Merge readiness

Recommendation: Not ready to merge yet.

The handler change itself looks reasonable, but I would address the two open review items above and refresh the PR description before merging.

Additional note: GitHub check metadata for this PR is not currently green from the data I could read (maui-pr shows failures and one run still appears in progress/pending). I did not investigate CI failures here because that is outside this skill's scope.

@kubaflo kubaflo added s/agent-approved AI agent recommends approval - PR fix is correct and optimal and removed s/agent-review-incomplete AI agent could not complete all phases (blocker, timeout, error) labels Mar 18, 2026
@github-actions
Copy link
Copy Markdown
Contributor

🚀 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 -- 33719

Or

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

@Shalini-Ashokan
Copy link
Copy Markdown
Contributor Author

@kubaflo, I addressed all the AI review concerns.

@kubaflo kubaflo changed the base branch from main to inflight/current March 18, 2026 12:59
@kubaflo kubaflo merged commit f8dbcff into dotnet:inflight/current Mar 18, 2026
22 of 31 checks passed
PureWeen pushed a commit that referenced this pull request Mar 19, 2026
…Scrolled after programmatic scroll (#33719)

<!-- 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. !!!!!!!
-->
### Issue Details
On iOS and MacCatalyst, the CollectionView.Scrolled event reports an
incorrect FirstVisibleItemIndex after a programmatic ScrollTo() call.
The reported index does not match the actual first visible item
displayed on the screen.

### Root Cause
The previous implementation used `IndexPathsForVisibleItems.First()` to
determine the first visible item. On iOS/MacCatalyst, that collection
can include prefetched cells outside the actual viewport, so the
reported first visible index could be earlier than the item shown at the
leading edge.

### Description of Change
Updated the iOS CollectionView delegators to compute the first visible
item from `LayoutAttributesForElementsInRect(...)` and select the first
visible cell that intersects the current viewport. This avoids relying
on prefetched cells when raising `Scrolled`.

Applied the fix to both:


[ItemsViewDelegator.cs](vscode-file://vscode-app/Applications/Visual%20Studio%20Code.app/Contents/Resources/app/out/vs/code/electron-browser/workbench/workbench.html)

[ItemsViewDelegator2.cs](vscode-file://vscode-app/Applications/Visual%20Studio%20Code.app/Contents/Resources/app/out/vs/code/electron-browser/workbench/workbench.html)

Validated the behavior in the following platforms
 
- [x] Android
- [x] Windows
- [x] iOS
- [x] Mac
 
### Issues Fixed
  
Fixes #33614

### Output  ScreenShot

|Before|After|
|--|--|
| <video
src="https://github.com/user-attachments/assets/484a1141-3cfc-470b-9637-39269679832b"
>| <video
src="https://github.com/user-attachments/assets/efe17504-4a79-4581-aabb-4443ef779580">|
PureWeen pushed a commit that referenced this pull request Mar 24, 2026
…Scrolled after programmatic scroll (#33719)

<!-- 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. !!!!!!!
-->
### Issue Details
On iOS and MacCatalyst, the CollectionView.Scrolled event reports an
incorrect FirstVisibleItemIndex after a programmatic ScrollTo() call.
The reported index does not match the actual first visible item
displayed on the screen.

### Root Cause
The previous implementation used `IndexPathsForVisibleItems.First()` to
determine the first visible item. On iOS/MacCatalyst, that collection
can include prefetched cells outside the actual viewport, so the
reported first visible index could be earlier than the item shown at the
leading edge.

### Description of Change
Updated the iOS CollectionView delegators to compute the first visible
item from `LayoutAttributesForElementsInRect(...)` and select the first
visible cell that intersects the current viewport. This avoids relying
on prefetched cells when raising `Scrolled`.

Applied the fix to both:


[ItemsViewDelegator.cs](vscode-file://vscode-app/Applications/Visual%20Studio%20Code.app/Contents/Resources/app/out/vs/code/electron-browser/workbench/workbench.html)

[ItemsViewDelegator2.cs](vscode-file://vscode-app/Applications/Visual%20Studio%20Code.app/Contents/Resources/app/out/vs/code/electron-browser/workbench/workbench.html)

Validated the behavior in the following platforms
 
- [x] Android
- [x] Windows
- [x] iOS
- [x] Mac
 
### Issues Fixed
  
Fixes #33614

### Output  ScreenShot

|Before|After|
|--|--|
| <video
src="https://github.com/user-attachments/assets/484a1141-3cfc-470b-9637-39269679832b"
>| <video
src="https://github.com/user-attachments/assets/efe17504-4a79-4581-aabb-4443ef779580">|
KarthikRajaKalaimani pushed a commit to KarthikRajaKalaimani/maui that referenced this pull request Mar 30, 2026
…Scrolled after programmatic scroll (dotnet#33719)

<!-- 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. !!!!!!!
-->
### Issue Details
On iOS and MacCatalyst, the CollectionView.Scrolled event reports an
incorrect FirstVisibleItemIndex after a programmatic ScrollTo() call.
The reported index does not match the actual first visible item
displayed on the screen.

### Root Cause
The previous implementation used `IndexPathsForVisibleItems.First()` to
determine the first visible item. On iOS/MacCatalyst, that collection
can include prefetched cells outside the actual viewport, so the
reported first visible index could be earlier than the item shown at the
leading edge.

### Description of Change
Updated the iOS CollectionView delegators to compute the first visible
item from `LayoutAttributesForElementsInRect(...)` and select the first
visible cell that intersects the current viewport. This avoids relying
on prefetched cells when raising `Scrolled`.

Applied the fix to both:


[ItemsViewDelegator.cs](vscode-file://vscode-app/Applications/Visual%20Studio%20Code.app/Contents/Resources/app/out/vs/code/electron-browser/workbench/workbench.html)

[ItemsViewDelegator2.cs](vscode-file://vscode-app/Applications/Visual%20Studio%20Code.app/Contents/Resources/app/out/vs/code/electron-browser/workbench/workbench.html)

Validated the behavior in the following platforms
 
- [x] Android
- [x] Windows
- [x] iOS
- [x] Mac
 
### Issues Fixed
  
Fixes dotnet#33614

### Output  ScreenShot

|Before|After|
|--|--|
| <video
src="https://github.com/user-attachments/assets/484a1141-3cfc-470b-9637-39269679832b"
>| <video
src="https://github.com/user-attachments/assets/efe17504-4a79-4581-aabb-4443ef779580">|
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/ios s/agent-approved AI agent recommends approval - PR fix is correct and optimal s/agent-fix-pr-picked AI could not beat the PR fix - PR is the best among all candidates s/agent-gate-passed AI verified tests catch the bug (fail without fix, pass with fix) s/agent-reviewed PR was reviewed by AI agent workflow (full 4-phase review)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[iOS, Mac] CollectionView Scrolled event reports incorrect FirstVisibleItemIndex after programmatic ScrollTo

7 participants