Skip to content

[Android/iOS] Fix CollectionView not respecting SafeAreaEdges settings#33908

Merged
kubaflo merged 4 commits intodotnet:inflight/currentfrom
praveenkumarkarunanithi:fix-33604
Mar 19, 2026
Merged

[Android/iOS] Fix CollectionView not respecting SafeAreaEdges settings#33908
kubaflo merged 4 commits intodotnet:inflight/currentfrom
praveenkumarkarunanithi:fix-33604

Conversation

@praveenkumarkarunanithi
Copy link
Copy Markdown
Contributor

@praveenkumarkarunanithi praveenkumarkarunanithi commented Feb 5, 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!

Root Cause

Android:
CollectionView uses RecyclerView which implements IMauiRecyclerView. When individual item views within the ItemTemplate have explicit SafeAreaEdges settings (e.g., <Grid SafeAreaEdges="Container,None">), these item views were excluded from receiving window inset listeners because of the || view is IMauiRecyclerView check in FindListenerForView(). This prevented per-item safe area control within CollectionView items.

iOS:
CollectionView uses UICollectionView, which inherits from UIScrollView. The RespondsToSafeArea() check excluded all UIScrollView descendants, preventing CollectionView cell content views from responding to safe area. Additionally, cell content views never receive SafeAreaInsetsDidChange() notifications during orientation changes, causing their SafeAreaInsets property to remain stale.

Description of Change

Android:
Removed the || parent is IMauiRecyclerView exclusion from FindListenerForView(). RecyclerView child views (CollectionView item views) can now receive window inset listeners, enabling SafeAreaEdges on individual item templates.

iOS:
Added an exception in RespondsToSafeArea() so that UICollectionView descendants respond to safe area even though they inherit from UIScrollView. For CollectionView descendants, Window.SafeAreaInsets is used instead of this.SafeAreaInsets to obtain current safe area values during layout. In CrossPlatformArrange(), safe area revalidation is forced when window insets change (such as during orientation changes), ensuring CollectionView cell content views update correctly.

Issues Fixed

Fixes #33604

Platforms Tested

  • iOS
  • Android
  • Windows
  • Mac

Note: Test scoped to iOS only — Android CI devices lack notch/cutout hardware, so SafeArea screenshot differences are not observable on that platform.

iOS Screenshots

Before Fix After Fix
iOS-withoutfix.1.mov
iOS-withfix.1.mov

Android Screenshots

Before Fix After Fix
Android-withoutfix.mov
Android-withfix.mov

@dotnet-policy-service dotnet-policy-service bot added the partner/syncfusion Issues / PR's with Syncfusion collaboration label Feb 5, 2026
@praveenkumarkarunanithi praveenkumarkarunanithi added platform/android platform/ios area-controls-collectionview CollectionView, CarouselView, IndicatorView and removed partner/syncfusion Issues / PR's with Syncfusion collaboration labels Feb 5, 2026
@karthikraja-arumugam karthikraja-arumugam added community ✨ Community Contribution partner/syncfusion Issues / PR's with Syncfusion collaboration labels Feb 5, 2026
@sheiksyedm sheiksyedm marked this pull request as ready for review February 18, 2026 12:39
Copilot AI review requested due to automatic review settings February 18, 2026 12:39
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 issue #33604 where CollectionView does not respect SafeAreaEdges settings on individual item templates. The issue manifested differently on Android (regression from 10.0.1 to 10.0.30) and iOS (never worked correctly). The fix enables per-item SafeAreaEdges control within CollectionView/CarouselView items on both platforms.

Changes:

  • Android: Removed IMauiRecyclerView exclusion from window inset listener lookup, allowing RecyclerView child views (CollectionView items) to receive inset listeners
  • iOS: Added UICollectionView exception to safe area handling so CollectionView cells can respond to safe area, using Window.SafeAreaInsets to work around iOS notification limitations

Reviewed changes

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

File Description
src/Core/src/Platform/iOS/MauiView.cs Added UICollectionView exception in RespondsToSafeArea(), implemented Window.SafeAreaInsets fallback for CollectionView cells, added safe area revalidation logic during orientation changes
src/Core/src/Platform/Android/MauiWindowInsetListener.cs Removed IMauiRecyclerView exclusion from FindListenerForView() to enable per-item SafeAreaEdges control

@rmarinho rmarinho added s/agent-changes-requested AI agent recommends changes - found a better alternative or issues 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
@praveenkumarkarunanithi praveenkumarkarunanithi force-pushed the fix-33604 branch 2 times, most recently from 874dec3 to 2739829 Compare February 20, 2026 10:46
@kubaflo kubaflo removed the s/agent-changes-requested AI agent recommends changes - found a better alternative or issues label Feb 25, 2026
@dotnet dotnet deleted a comment from rmarinho Mar 14, 2026
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.

Could you please resolve conflicts?

@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 -- 33908

Or

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

@praveenkumarkarunanithi
Copy link
Copy Markdown
Contributor Author

Could you please resolve conflicts?

Conflicts have been resolved and the branch has been updated accordingly.

@sheiksyedm
Copy link
Copy Markdown
Contributor

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

@azure-pipelines
Copy link
Copy Markdown

Azure Pipelines successfully started running 2 pipeline(s).

@AlleSchonWeg
Copy link
Copy Markdown
Contributor

Hi,
i have a question to this PR.
Will the fix also works for other CollectionViews? From DevExpress and Syncfusion? Or only Maui CollectionViews?

@praveenkumarkarunanithi
Copy link
Copy Markdown
Contributor Author

📋 PR Finalization Review

Title: ✅ Good

Current: [Android/iOS] Fix CollectionView not respecting SafeAreaEdges settings

Description: ✅ Good

The description is well-structured with:

Only concern: PR diff includes ~15 unrelated files from merging upstream/main (.github/, eng/, TypedBinding changes from #34428). Consider rebasing to focus the diff on the actual CollectionView SafeArea fix.

Code Review: ⚠️ Issues Found

🟡 Suggestions

1. Consider pixel-level comparison for Window insets change detection

  • File: src/Core/src/Platform/iOS/MauiView.cs (line ~552 in CrossPlatformArrange)
  • Current code: !currentWindowInsets.Equals(_lastWindowSafeAreaInsets) uses exact UIEdgeInsets struct comparison
  • Concern: The codebase convention is EqualsAtPixelLevel() for safe area comparisons (used in ValidateSafeArea() at line 692 and MauiScrollView.cs:406) to absorb sub-pixel animation noise. While the downstream ValidateSafeArea() has pixel-level protection preventing oscillation, using exact comparison here triggers unnecessary ValidateSafeArea() recalculation calls during animation transitions.
  • Suggestion: Convert UIEdgeInsets to SafeAreaPadding (via ToSafeAreaInsets()) and use EqualsAtPixelLevel() for consistency:
var currentWindowPadding = currentWindowInsets.ToSafeAreaInsets();
if (!currentWindowPadding.EqualsAtPixelLevel(_lastWindowSafeAreaPadding))

2. No automated tests for the CollectionView SafeArea fix

3. Merge noise from upstream/main

  • PR includes ~15 unrelated files (.github/, eng/, TypedBinding.cs, TypedBindingUnitTests.cs) from merging upstream/main into the feature branch
  • This makes the diff harder to review. Consider rebasing onto the target branch (inflight/current) to keep the diff focused

4. Minor: trailing double blank line

  • File: src/Core/src/Platform/iOS/MauiView.cs (around line 318)
  • Two consecutive blank lines after the ternary in GetAdjustedSafeAreaInsets() — minor style nit

✅ Looks Good

  • Android change is surgical and safe — removing || parent is IMauiRecyclerView from FindListenerForView() is minimal and well-commented. The comment about performance overhead being negligible is appreciated
  • iOS RespondsToSafeArea() logic is correct — properly distinguishes UICollectionView from regular UIScrollView using scrollViewParent is not UICollectionView
  • Cache invalidation is complete_collectionViewDescendant, _lastWindowSafeAreaInsets, and _scrollViewDescendant are all properly cleared in MovedToWindow()
  • Null-safe nullable bool access_collectionViewDescendant == true correctly handles the bool? type (null and false both evaluate to false)
  • TypedBinding Subscribe() idempotency claim is verified — The PropertyChangedProxy.Part setter uses ReferenceEquals to skip if already subscribed to the same source, confirming the "safe to call repeatedly" comment
  • Window.SafeAreaInsets as data source for CollectionView cells is a reasonable trade-off — cells do not receive SafeAreaInsetsDidChange notifications, so using window-level insets (which always reflect current orientation) is the correct workaround

Addressed AI summary review concerns, and added a UI test for CollectionView SafeArea validation (iOS only).

@MauiBot
Copy link
Copy Markdown
Collaborator

MauiBot commented Mar 19, 2026

🤖 AI Summary

📊 Expand Full Review92d702a · updated test and addressed AI agent concerns.
🔍 Pre-Flight — Context & Validation

Issue: #33604 - CollectionView does not respect content SafeAreaEdges choices (Regression for Android, different problem in iOS)
PR: #33908 - [Android/iOS] Fix CollectionView not respecting SafeAreaEdges settings
Platforms Affected: Android, iOS
Files Changed: 2 implementation, 2 test, 1 snapshot

Key Findings

  • The linked issue describes two different failures: Android regressed in 10.0.10 and lets CollectionView item content render under system bars, while iOS keeps both background and content inside the safe area instead of allowing container/background bleed.
  • The PR changes Android and iOS platform code plus adds an iOS-only UI test (Issue33604) and baseline screenshot; the PR description explicitly notes Android notch/cutout validation is not observable on CI devices.
  • Prior review feedback asked for pixel-level safe-area comparison consistency and automated test coverage; the author replied that the concerns were addressed and added the iOS UI test.
  • An open PR discussion question asks whether the fix helps third-party CollectionView implementations (for example DevExpress or Syncfusion); there is no visible answer yet.
  • Current PR checks are still running, while Windows Helix unit test lanes are red; those failures do not appear tied to the 5-file PR diff from GitHub.

Edge Cases From Discussion

  • iOS behavior was reported as reproducible on iOS 26.1 but not on iOS 18.0 or 26.0 in issue validation comments, so orientation/safe-area timing differences across OS versions matter.
  • The desired behavior is mixed: CollectionView item backgrounds should extend edge-to-edge while inner content still respects safe area when SafeAreaEdges="Container,None" is used inside item templates.
  • PR comments imply collection-view descendants need special handling without regressing ordinary UIScrollView descendant behavior.

File Classification

  • Implementation:
    • src/Core/src/Platform/Android/MauiWindowInsetListener.cs
    • src/Core/src/Platform/iOS/MauiView.cs
  • UI test assets:
    • src/Controls/tests/TestCases.HostApp/Issues/Issue33604.cs
    • src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue33604.cs
    • src/Controls/tests/TestCases.iOS.Tests/snapshots/ios/CollectionViewItemsShouldRespectSafeAreaEdges.png

Fix Candidates

# Source Approach Test Result Files Changed Notes
PR PR #33908 Android: allow RecyclerView item descendants to receive inset listeners. iOS: let UICollectionView descendants participate in safe-area handling and revalidate using window safe-area padding during layout/orientation PENDING (Gate) MauiWindowInsetListener.cs, MauiView.cs, Issue33604.cs (HostApp/UI test), snapshot Original PR plus iOS-only UI regression test changes.

🚦 Gate — Test Verification

Gate Result: PASSED

Platform: ios
Mode: Full Verification

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

Evidence

  • Used verify-tests-fail.ps1 with -FixFiles override to target the PR implementation files despite noisy local diff state.
  • Verification report: CustomAgentLogsTmp/PRState/33908/PRAgent/gate/verify-tests-fail/verification-report.md
  • The report records Tests WITHOUT fix | FAIL | FAIL | PASS and Tests WITH fix | PASS | PASS | PASS for Issue33604 on iOS.

🔧 Fix — Analysis & Comparison

Fix Candidates

# Source Approach Test Result Files Changed Notes
1 try-fix (claude-opus-4.6) Force CollectionView descendant invalidation in LayoutSubviews() and keep using per-cell SafeAreaInsets instead of window padding. FAIL src/Core/src/Platform/iOS/MauiView.cs Functionally closer, but screenshot still differed by 5.88 percent, so it did not match the expected baseline.
2 try-fix (claude-sonnet-4.6) Invalidate CollectionView descendants from TraitCollectionDidChange() while still using Window.SafeAreaInsets. PASS src/Core/src/Platform/iOS/MauiView.cs, src/Core/src/PublicAPI/net-ios/PublicAPI.Unshipped.txt Passed the screenshot, but it introduced a new override/API entry and a PublicAPI change, making it heavier than the PR fix.
3 try-fix (gpt-5.3-codex) Propagate safe-area invalidation from ancestor SafeAreaInsetsDidChange() into UICollectionView descendants while relying on collection-parent/cell inset propagation. FAIL src/Core/src/Platform/iOS/MauiView.cs Also failed the screenshot by 5.88 percent, reinforcing that ancestor/cell inset propagation alone does not match the expected layout.
4 try-fix (gemini-3-pro-preview) Use a geometric Window.SafeAreaInsets intersection fallback for collection descendants instead of the PR's arrange-time cache/revalidation pattern. FAIL src/Core/src/Platform/iOS/MauiView.cs, src/Controls/tests/TestCases.Shared.Tests/UITest.cs Still produced portrait-style/stale inset behavior in the test run and missed the screenshot baseline.
5 try-fix (gpt-5.3-codex, cross-pollination) Hard-disable per-cell safe-area handling for UICollectionViewCell descendants and push compensation to the container chain only. FAIL src/Core/src/Platform/iOS/MauiView.cs, src/Core/src/Platform/iOS/MauiScrollView.cs Test command failed before behavioral validation because the local baseline drifted into the known ImageMagick compile mismatch.
6 try-fix (gemini-3-pro-preview, cross-pollination) Enable PreservesSuperviewLayoutMargins on UICollectionViewCell / ContentView to lean on UIKit inset propagation. BLOCKED src/Controls/src/Core/Handlers/Items2/iOS/ItemsViewCell2.cs Also blocked by the same local ImageMagick compile drift before the idea could be behaviorally validated.
PR PR #33908 Distinguish UICollectionView descendants from ordinary UIScrollView descendants, source CollectionView cell safe-area values from Window.SafeAreaInsets, and force revalidation during arrange when window padding changes. PASSED (Gate) src/Core/src/Platform/iOS/MauiView.cs, src/Core/src/Platform/Android/MauiWindowInsetListener.cs, Issue33604 UI test files Original PR validated on iOS via full fail-without-fix / pass-with-fix gate verification.

Cross-Pollination

Model Round New Ideas? Details
claude-opus-4.6 2 No NO NEW IDEAS
claude-sonnet-4.6 2 No NO NEW IDEAS
gpt-5.3-codex 2 Yes NEW IDEA: For any MauiView/MauiScrollView inside a UICollectionViewCell, hard-disable per-cell safe-area application and apply compensation once at the UICollectionView container level only.
gemini-3-pro-preview 2 Yes NEW IDEA: Enable PreservesSuperviewLayoutMargins on the UICollectionViewCell and its ContentView to rely on UIKit's native inset propagation mechanism.
claude-opus-4.6 3 No NO NEW IDEAS
claude-sonnet-4.6 3 Yes NEW IDEA: Drive compensation from the nearest UIViewController's ViewSafeAreaInsetsDidChange / UIViewController.View.SafeAreaInsets.
gpt-5.3-codex 3 Yes NEW IDEA: Set ContentInsetAdjustmentBehavior = Never and apply Window safe area via FlowLayout.SectionInset manually.
gemini-3-pro-preview 3 No NO NEW IDEAS

Exhausted: Yes - max 3 cross-pollination rounds reached.
Selected Fix: PR #33908 - It is the simplest passing implementation: validated by full gate verification, avoids the extra PublicAPI/API surface required by Attempt 2, and directly addresses both the stale inset source and invalidation timing problem for CollectionView cells.


📋 Report — Final Recommendation

Final Recommendation: APPROVE

Phase Status

Phase Status Notes
Pre-Flight COMPLETE Issue/PR context, file classification, discussion edge cases, and current check status documented.
Gate PASSED iOS full verification proved Issue33604 fails without the fix and passes with the fix.
Try-Fix COMPLETE 6 attempts explored; 1 alternative passed, but it was heavier and expanded API surface compared to the PR fix.
Report COMPLETE

Summary

PR #33908 fixes the iOS CollectionView safe-area regression by letting UICollectionView descendants participate in safe-area handling, using Window.SafeAreaInsets as the reliable source for CollectionView cell layout, and forcing revalidation when those window insets change. The new iOS UI regression test (Issue33604) correctly catches the bug: it failed without the fix and passed with the fix during gate verification.

Try-fix exploration found only one passing alternative: an event-driven TraitCollectionDidChange() version that still depended on Window.SafeAreaInsets. That alternative added a new override/API surface and required a PublicAPI update, making it less surgical than the PR's existing arrange-time revalidation approach. Other alternatives either consistently missed the screenshot baseline by 5.88 percent or were blocked by local baseline drift in the ImageMagick test dependency.

Root Cause

UICollectionView inherits from UIScrollView, so MAUI's existing iOS safe-area logic treated CollectionView descendants like ordinary scroll-view children and skipped their safe-area participation. On rotation, CollectionView cell content also does not reliably receive fresh per-cell SafeAreaInsets, leaving stale values in the cell subtree. Fixing the bug therefore requires both:

  • an exception so CollectionView descendants are allowed to participate in safe-area handling, and
  • a reliable source of current safe-area values plus a revalidation trigger when orientation/window insets change.

Fix Quality

The PR's fix is the best candidate from the review:

  • It passed full fail-without-fix / pass-with-fix verification on iOS.
  • It solves both parts of the root cause: descendant eligibility and stale safe-area values after rotation.
  • It is more contained than the only passing alternative because it avoids adding new API/PublicAPI surface.
  • The added UI regression test is appropriately scoped to iOS, where notch/cutout behavior is observable and relevant for this bug.

@MauiBot MauiBot added the s/agent-approved AI agent recommends approval - PR fix is correct and optimal label Mar 19, 2026
@kubaflo kubaflo merged commit f1b83d6 into dotnet:inflight/current Mar 19, 2026
30 of 36 checks passed
PureWeen pushed a commit that referenced this pull request Mar 24, 2026
#33908)

<!-- Please let the below note in for people that find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!

### Root Cause
Android:
CollectionView uses `RecyclerView` which implements `IMauiRecyclerView`.
When individual item views within the ItemTemplate have explicit
SafeAreaEdges settings (e.g., `<Grid SafeAreaEdges="Container,None">`),
these item views were excluded from receiving window inset listeners
because of the `|| view is IMauiRecyclerView` check in
`FindListenerForView()`. This prevented per-item safe area control
within CollectionView items.

iOS:
CollectionView uses `UICollectionView`, which inherits from
`UIScrollView`. The `RespondsToSafeArea()` check excluded all
`UIScrollView` descendants, preventing CollectionView cell content views
from responding to safe area. Additionally, cell content views never
receive `SafeAreaInsetsDidChange()` notifications during orientation
changes, causing their `SafeAreaInsets` property to remain **stale**.

### Description of Change

Android:
Removed the `|| parent is IMauiRecyclerView` exclusion from
`FindListenerForView()`. RecyclerView child views (CollectionView item
views) can now receive window inset listeners, enabling `SafeAreaEdges`
on individual item templates.

iOS:
Added an exception in `RespondsToSafeArea()` so that `UICollectionView`
descendants respond to safe area even though they inherit from
`UIScrollView`. For CollectionView descendants, `Window.SafeAreaInsets`
is used instead of `this.SafeAreaInsets` to obtain current safe area
values during layout. In `CrossPlatformArrange()`, safe area
revalidation is forced when window insets change (such as during
orientation changes), ensuring CollectionView cell content views update
correctly.

### Issues Fixed

Fixes #33604 

### Platforms Tested

- [x] iOS
- [x] Android  
- [x] Windows
- [x] Mac

**Note:** Test scoped to iOS only — Android CI devices lack notch/cutout
hardware, so SafeArea screenshot differences are not observable on that
platform.

### iOS Screenshots
| Before Fix | After Fix |
|------------|-----------|
| <video width="350" alt="withoutfix"
src="https://github.com/user-attachments/assets/466ca15c-db77-45ff-8cfb-2d2042ca3b2d"
/> | <video width="350" alt="withfix"
src="https://github.com/user-attachments/assets/33f9ea89-a8bd-40c8-b4d8-cb0e7d93348c"
/> |

### Android Screenshots
| Before Fix | After Fix |
|------------|-----------|
| <video width="350" alt="withoutfix"
src="https://github.com/user-attachments/assets/df310e84-67a7-42cd-adc0-7f91af1a1d36"
/> | <video width="350" alt="withfix"
src="https://github.com/user-attachments/assets/70c4d21c-5ccc-4492-9bcb-9ee03d6a25c7"
/> |
kubaflo added a commit that referenced this pull request Mar 25, 2026
Adds a new skill and gh-aw workflow that detects if a PR modifies or
reverts code from a recent bug-fix PR, which could re-introduce a
previously-fixed bug.

Motivation: Three P/0 regressions (#34634, #34635, #34636) shipped in
10.0.60 because the agent approved PRs that unknowingly reverted lines
from prior fix PRs. This skill would have caught them — e.g., PR #33908
removed a line from PR #32278 that fixed #32436, and the exact same bug
reappeared.

How it works:
- For each implementation file in the PR diff, queries git log for
  recent PRs (6 months)
- Checks if those PRs were bug fixes (via PR labels or linked issue
  labels: i/regression, t/bug, p/0, p/1)
- Compares lines ADDED by fix PRs against lines REMOVED by the current
  PR
- Reports revert risks (🔴), overlaps (🟡), or clean (🟢)

Triggers:
- pull_request: auto on src/**/*.cs or src/**/*.xaml changes
- workflow_dispatch: manual — enter PR number
- issue_comment: /check-regression on a PR

Files:
- .github/skills/find-regression-risk/SKILL.md
- .github/skills/find-regression-risk/scripts/Find-RegressionRisks.ps1
- .github/workflows/copilot-find-regression-risk.md
- .github/workflows/copilot-find-regression-risk.lock.yml
- .github/aw/actions-lock.json (updated)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions
Copy link
Copy Markdown
Contributor

🔍 Regression Risk Analysis

🟡 Overlaps found — This PR modifies files that were recently changed by bug-fix PRs, but does not revert their fix lines.

👍 / 👎 — Was this analysis helpful? React to let us know!

📊 Expand Full Analysis
File Recent Fix PR Fixed Issue Risk
src/Core/src/Platform/iOS/MauiView.cs #34024 — [iOS] Fix SafeArea infinite layout cycle with parent hierarchy walk and pixel-level comparison #33595, #32586 🟡 Overlap
src/Core/src/Platform/iOS/MauiView.cs #33526 — [iOS] SafeArea: Return Empty for non-ISafeAreaView views (opt-in model) 🟡 Overlap
src/Core/src/Platform/iOS/MauiView.cs #32064 — Fix SafeAreaEdges.SoftInput applying bottom padding when keyboard is hidden 🟡 Overlap
src/Core/src/Platform/Android/MauiWindowInsetListener.cs #33428 — [Android] Fix for TabbedPage BottomNavigation BarBackgroundColor not extending to system navigation bar #33344 🟡 Overlap
src/Core/src/Platform/Android/MauiWindowInsetListener.cs #32064 — Fix SafeAreaEdges.SoftInput applying bottom padding when keyboard is hidden 🟡 Overlap

Notes

Note

🔒 Integrity filtering filtered 5 items

Integrity filtering activated and filtered the following items during workflow execution.
This happens when a tool call accesses a resource that does not meet the required integrity or secrecy level of the workflow.

🔍 Regression risk analysis by Find Regression Risk

PureWeen pushed a commit that referenced this pull request Mar 25, 2026
Add a new mandatory regression detection step to the pr-finalize code review
workflow that catches PRs which inadvertently revert lines added by prior bug fixes.

## Problem

Three P/0 regressions (#34634, #34635, #34636) shipped in 10.0.60 because the
agent approved PRs that unknowingly reverted lines from prior fix PRs. Specifically,
PR #33908 removed `|| parent is IMauiRecyclerView` from MauiWindowInsetListener.cs
— a line PR #32278 added to fix issue #32436 — causing that bug to reappear.

The agent's code review had no mechanism to detect this 'reverted fix' pattern.

## Changes

### .github/skills/pr-finalize/SKILL.md
- Add "Prior Fix Regression Check" as Step 1 of Phase 2 (Code Review)
- Documents the pattern with the real MauiWindowInsetListener.cs example
- Specifies what to flag as 🔴 Critical and what to output

### .github/skills/pr-finalize/scripts/Detect-Regressions.ps1
- New PowerShell script that automates regression detection
- Gets PR diff, extracts deleted lines from implementation files
- Runs git blame to find originating commits
- Flags lines whose commit references an issue number (fixes #XXXX)
- Exits with code 1 if regressions detected (integrates with CI)

### .github/skills/pr-finalize/tests/eval.yaml
- Eval test cases for the pr-finalize skill
- Covers: regression detected (should flag), benign removal (should not flag),
  refactoring commit (should not flag), multiple regressions, general code review

### .github/instructions/regression-detection.instructions.md
- Global instruction file documenting the reverted-fix anti-pattern
- Explains detection method (git blame on deleted lines)
- Lists high-risk MAUI code patterns prone to this issue
- Guidance for PR authors on how to document intentional removals

### .github/copilot-instructions.md
- Add regression detection step to the Code Review Instructions section

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
KarthikRajaKalaimani pushed a commit to KarthikRajaKalaimani/maui that referenced this pull request Mar 30, 2026
dotnet#33908)

<!-- Please let the below note in for people that find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!

### Root Cause
Android:
CollectionView uses `RecyclerView` which implements `IMauiRecyclerView`.
When individual item views within the ItemTemplate have explicit
SafeAreaEdges settings (e.g., `<Grid SafeAreaEdges="Container,None">`),
these item views were excluded from receiving window inset listeners
because of the `|| view is IMauiRecyclerView` check in
`FindListenerForView()`. This prevented per-item safe area control
within CollectionView items.

iOS:
CollectionView uses `UICollectionView`, which inherits from
`UIScrollView`. The `RespondsToSafeArea()` check excluded all
`UIScrollView` descendants, preventing CollectionView cell content views
from responding to safe area. Additionally, cell content views never
receive `SafeAreaInsetsDidChange()` notifications during orientation
changes, causing their `SafeAreaInsets` property to remain **stale**.

### Description of Change

Android:
Removed the `|| parent is IMauiRecyclerView` exclusion from
`FindListenerForView()`. RecyclerView child views (CollectionView item
views) can now receive window inset listeners, enabling `SafeAreaEdges`
on individual item templates.

iOS:
Added an exception in `RespondsToSafeArea()` so that `UICollectionView`
descendants respond to safe area even though they inherit from
`UIScrollView`. For CollectionView descendants, `Window.SafeAreaInsets`
is used instead of `this.SafeAreaInsets` to obtain current safe area
values during layout. In `CrossPlatformArrange()`, safe area
revalidation is forced when window insets change (such as during
orientation changes), ensuring CollectionView cell content views update
correctly.

### Issues Fixed

Fixes dotnet#33604 

### Platforms Tested

- [x] iOS
- [x] Android  
- [x] Windows
- [x] Mac

**Note:** Test scoped to iOS only — Android CI devices lack notch/cutout
hardware, so SafeArea screenshot differences are not observable on that
platform.

### iOS Screenshots
| Before Fix | After Fix |
|------------|-----------|
| <video width="350" alt="withoutfix"
src="https://github.com/user-attachments/assets/466ca15c-db77-45ff-8cfb-2d2042ca3b2d"
/> | <video width="350" alt="withfix"
src="https://github.com/user-attachments/assets/33f9ea89-a8bd-40c8-b4d8-cb0e7d93348c"
/> |

### Android Screenshots
| Before Fix | After Fix |
|------------|-----------|
| <video width="350" alt="withoutfix"
src="https://github.com/user-attachments/assets/df310e84-67a7-42cd-adc0-7f91af1a1d36"
/> | <video width="350" alt="withfix"
src="https://github.com/user-attachments/assets/70c4d21c-5ccc-4492-9bcb-9ee03d6a25c7"
/> |
kubaflo pushed a commit that referenced this pull request Mar 31, 2026
…candidate branch (#34667)

<!-- 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!
  
**Reverts the iOS-specific `Window.SafeAreaInsets` changes that caused
CollectionView cell misalignment on the candidate branch from #33908 ,
and re-implements safe area handling via per-cell geometric overlap
computation that works correctly across all platforms.**
 
### Root Cause
**Cause of regression:**
PR #33908 introduced the issue by using `Window.SafeAreaInsets` for
`CollectionView` cells; on macOS this includes a 41px title bar. Due to
a timing race (`IsParentHandlingSafeArea()` returning false), all cells
incorrectly applied this inset, causing misalignment.
Reverted the iOS changes from PR #33908 in MauiView.cs, restoring the
previous behavior. Android changes were retained as they function
correctly.

**Actual root cause of Issue33604:**
PR #33908 modified `MauiView.GetAdjustedSafeAreaInsets()` to use
`Window.SafeAreaInsets` as the base safe area for CollectionView cell
descendants. On macOS, `Window.SafeAreaInsets.Top` is 41px (title bar).
Combined with `IsParentHandlingSafeArea()` returning false due to a
timing race (parent not yet validated), every CollectionView cell
received `_appliesSafeAreaAdjustments = true` with a 41px top inset,
causing all items to be misaligned on MacCatalyst.
Fix: Fully reverted all iOS changes from PR #33908 in MauiView.cs,
restoring it to the pre-#33908 state. The Android changes from PR #33908
are retained as they work correctly (WindowInsetsCompat propagates to
all views regardless of `RecyclerView` containment).
 
### Description of Change
The fix introduces a shared helper in `MauiView`
(`ApplyCellSafeAreaOverride` / `ComputeCellSafeAreaInsets`) used by both
`TemplatedCell` (CV1) and `TemplatedCell2` (CV2) during
`LayoutSubviews`.

Before arranging, per-cell safe area insets are computed based on the
cell's geometric position relative to the window's unsafe regions and
passed via a new `CellSafeAreaOverride` property. The cell frame remains
full-width so backgrounds extend edge-to-edge, while content is inset
internally.

Uniform configurations (`Container×4`, `None×4`, `All×4`) are skipped as
they are handled by the parent layout. Insets are applied only for edges
explicitly set to `Container` or `All`, and ignored for `SoftInput`-only
edges. A tolerance filter (`ToSafeAreaInsets`) avoids sub-pixel layout
noise.

`MauiView` applies this override during `CrossPlatformMeasure` and
`CrossPlatformArrange` when `_appliesSafeAreaAdjustments` is false,
treating it as internal padding consistent with existing
`AdjustForSafeArea` behavior. Stale overrides are cleared during cell
reuse when the template no longer implements `ISafeAreaView2`.

Additionally, `ContentInsetsReference` is set to
`UIContentInsetsReference.None` at all three section creation sites in
`LayoutFactory2` (Linear, Grid, Carousel). On iOS 26.1+, the default
(`.automatic` → `.safeArea`) started actively insetting cells at the
section level in `UICollectionViewCompositionalLayout`, conflicting with
MAUI's internal safe area handling. Setting `.None` restores pre-26.1
behavior. CV1 is unaffected as it uses `UICollectionViewFlowLayout`,
which does not have this property.

### Issues Fixed
Fixes #33604 
Fixes #34635 

### Additional Fixes
Also resolves the following Failed iOS test cases:
`VerifyGroupFooterTemplate_WithFooterString`
`VerifyGroupHeaderTemplate_WithFooterString`
`VerifyIsGroupedFalse_WithHeaderAndFooterString`
`SelectedItemVisualIsCleared`
`CollectionViewItemsShouldRespectSafeAreaEdges`
 
Tested the behaviour in the following platforms
- [x] Android
- [ ] Windows
- [x] iOS
- [x] Mac

### Screenshots
**Issue33604**
| Before Fix | After Fix |
|------------|-----------|
| <video width="350" alt="withoutfix"
src="https://github.com/user-attachments/assets/466ca15c-db77-45ff-8cfb-2d2042ca3b2d"
/> | <video width="350" alt="withfix"
src="https://github.com/user-attachments/assets/33f9ea89-a8bd-40c8-b4d8-cb0e7d93348c"
/> |

**Issue34635**
| Before Fix | After Fix |
|------------|-----------|
| <video width="350" alt="withoutfix"
src="https://github.com/user-attachments/assets/783cc1ba-f18d-4aa2-8102-2e217f32ccc9"
/> | <video width="350" alt="withfix"
src="https://github.com/user-attachments/assets/9b6e8107-20d0-4a71-b2b5-3030a2db317c"
/> |
kubaflo added a commit that referenced this pull request Apr 1, 2026
Two bugs fixed:
1. .Count failed on non-array returns in strict mode — wrapped
   Get-IssueReferences calls in @() to ensure array type
2. Script missed regressions where the originating commit only had
   'fixes #XXXX' in the PR description, not the commit message.
   Now when a commit references a PR via (#XXXX) but has no issue
   refs in its message, the script queries the PR body via gh CLI.

Also fixed issue ref formatting in the report (#32301, 32436 → #32301, #32436).

Verified: correctly detects PR #33908 removing the IMauiRecyclerView
guard that was added by PR #32278 to fix issue #32436.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
kubaflo added a commit that referenced this pull request Apr 1, 2026
Adds Prior Fix Regression Check that detects when PRs remove lines
that were added by prior bug fixes (e.g. PR #33908 removing a guard
added by PR #32278 to fix issue #32436).

Files:
- copilot-regression-check.md/.lock.yml — gh-aw workflow
- Detect-Regressions.ps1 — detection script (checks commit msgs + PR bodies)
- eval.yaml — 11 eval scenarios
- regression-detection.instructions.md — global instructions
- SKILL.md — updated pr-finalize skill with regression check

Triggers: pull_request (no paths filter, gate step instead),
issue_comment (/check-regressions), workflow_dispatch (pr_number)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 1, 2026

🔍 Prior Fix Regression Check

Result:No prior fix regressions detected

Checked deleted lines across implementation files. No lines were identified as reversions of prior bug fixes.

👍 / 👎 — Was this check helpful? React to let us know!

🔍 Regression check by Prior Fix Regression Check

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 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-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 does not respect content SafeAreaEdges choices (Regression for Android, different problem in iOS)

8 participants