|
6 | 6 | using Microsoft.Maui.Controls.Internals; |
7 | 7 | using Microsoft.Maui.Controls.Platform; |
8 | 8 | using Microsoft.Maui.Graphics; |
| 9 | +using Microsoft.Maui.Platform; |
9 | 10 | using UIKit; |
10 | 11 |
|
11 | 12 | namespace Microsoft.Maui.Controls.Handlers.Items |
@@ -136,10 +137,71 @@ public override void LayoutSubviews() |
136 | 137 | // We now have to apply the new bounds size to the virtual view |
137 | 138 | // which will automatically set the frame on the platform view too. |
138 | 139 | var frame = new Rect(Point.Zero, boundsSize); |
| 140 | + |
| 141 | + // Inject per-cell safe area insets into the MauiView for CrossPlatformArrange |
| 142 | + // to apply as internal padding. UICollectionView bypasses MAUI's arrange chain, |
| 143 | + // so cells cannot use the standard safe area flow (#33604, #34635). |
| 144 | + if (virtualView is ISafeAreaView2 safeView && PlatformHandler.ToPlatform() is MauiView mauiView) |
| 145 | + { |
| 146 | + var insets = ComputeCellSafeAreaInsets(safeView); |
| 147 | + mauiView.CellSafeAreaOverride = insets != UIEdgeInsets.Zero |
| 148 | + ? insets.ToSafeAreaInsets() |
| 149 | + : SafeAreaPadding.Empty; |
| 150 | + } |
| 151 | + else if (PlatformHandler.ToPlatform() is MauiView mv && !mv.CellSafeAreaOverride.IsEmpty) |
| 152 | + { |
| 153 | + // Clear stale override from a previous template that implemented ISafeAreaView2. |
| 154 | + mv.CellSafeAreaOverride = SafeAreaPadding.Empty; |
| 155 | + } |
| 156 | + |
139 | 157 | virtualView.Arrange(frame); |
140 | 158 | } |
141 | 159 | } |
142 | 160 |
|
| 161 | + /// <summary> |
| 162 | + /// Computes per-cell safe area insets based on geometric overlap with the window's unsafe regions. |
| 163 | + /// Returns <see cref="UIEdgeInsets.Zero"/> when all edges share the same region (e.g., default |
| 164 | + /// Container×4), as the parent layout chain handles uniform safe area (#33604, #34635). |
| 165 | + /// </summary> |
| 166 | + UIEdgeInsets ComputeCellSafeAreaInsets(ISafeAreaView2 safeView) |
| 167 | + { |
| 168 | + var window = Window; |
| 169 | + if (window is null) |
| 170 | + return UIEdgeInsets.Zero; |
| 171 | + |
| 172 | + var windowSA = window.SafeAreaInsets; |
| 173 | + if (windowSA == UIEdgeInsets.Zero) |
| 174 | + return UIEdgeInsets.Zero; |
| 175 | + |
| 176 | + var leftRegion = safeView.GetSafeAreaRegionsForEdge(0); |
| 177 | + var topRegion = safeView.GetSafeAreaRegionsForEdge(1); |
| 178 | + var rightRegion = safeView.GetSafeAreaRegionsForEdge(2); |
| 179 | + var bottomRegion = safeView.GetSafeAreaRegionsForEdge(3); |
| 180 | + |
| 181 | + // Uniform edges (Container×4, None×4, All×4) are handled by the parent layout chain. |
| 182 | + bool allSameRegion = leftRegion == topRegion |
| 183 | + && topRegion == rightRegion |
| 184 | + && rightRegion == bottomRegion; |
| 185 | + |
| 186 | + if (allSameRegion) |
| 187 | + return UIEdgeInsets.Zero; |
| 188 | + |
| 189 | + // Only apply insets for Container edges; SoftInput-only edges are excluded. |
| 190 | + var cellInWindow = ConvertRectToView(Bounds, window); |
| 191 | + var windowBounds = window.Bounds; |
| 192 | + |
| 193 | + nfloat left = SafeAreaEdges.IsContainer(leftRegion) && windowSA.Left > 0 |
| 194 | + ? (nfloat)Math.Max(0, (double)(windowSA.Left - cellInWindow.X)) : 0; |
| 195 | + nfloat top = SafeAreaEdges.IsContainer(topRegion) && windowSA.Top > 0 |
| 196 | + ? (nfloat)Math.Max(0, (double)(windowSA.Top - cellInWindow.Y)) : 0; |
| 197 | + nfloat right = SafeAreaEdges.IsContainer(rightRegion) && windowSA.Right > 0 |
| 198 | + ? (nfloat)Math.Max(0, (double)(cellInWindow.Right - (windowBounds.Width - windowSA.Right))) : 0; |
| 199 | + nfloat bottom = SafeAreaEdges.IsContainer(bottomRegion) && windowSA.Bottom > 0 |
| 200 | + ? (nfloat)Math.Max(0, (double)(cellInWindow.Bottom - (windowBounds.Height - windowSA.Bottom))) : 0; |
| 201 | + |
| 202 | + return new UIEdgeInsets(top, left, bottom, right); |
| 203 | + } |
| 204 | + |
143 | 205 | [Obsolete] |
144 | 206 | [EditorBrowsable(EditorBrowsableState.Never)] |
145 | 207 | protected void Layout(CGSize constraints) |
|
0 commit comments