Skip to content

Implement SafeAreaEdges property for per-edge safe area control#30337

Merged
StephaneDelcroix merged 34 commits intonet10.0from
copilot/fix-28986
Jul 28, 2025
Merged

Implement SafeAreaEdges property for per-edge safe area control#30337
StephaneDelcroix merged 34 commits intonet10.0from
copilot/fix-28986

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Jun 30, 2025

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!

SafeArea Feature Specification

Caution as you test this PR

The safe area calculations in some scenarios are off until we can merge this PR #30629. These aren't bugs with this PR they are general bugs we've been trying to fix for sometimes.

  • If you have a control that you want hugging under the notch or top of screen it will be slightly cutoff
  • On SCrollView setting different edges or "ALL" will currently layout incorrectly on the bottom

Overview

The SafeArea feature provides fine-grained, per-edge safe area control for .NET MAUI applications, enabling developers to selectively control safe area behavior on specific edges while maintaining backward compatibility.

Public APIs

1. SafeAreaRegions Enum

[Flags]
public enum SafeAreaRegions
{
    None = 0,          // Edge-to-edge content (no safe area padding)
    SoftInput = 1,     // Always pad for keyboard/soft input
    Container = 2,     // Flow under keyboard, stay out of bars/notch  
    Default = 4,       // Platform default behavior
    All = int.MaxValue // Obey all safe area insets
}

2. SafeAreaEdges Struct

[TypeConverter(typeof(Converters.SafeAreaEdgesTypeConverter))]
public struct SafeAreaEdges : IEquatable<SafeAreaEdges>
{
    public SafeAreaRegions Left { get; set; }
    public SafeAreaRegions Top { get; set; }
    public SafeAreaRegions Right { get; set; }
    public SafeAreaRegions Bottom { get; set; }
    
    // Constructors
    public SafeAreaEdges(SafeAreaRegions uniformValue)
    public SafeAreaEdges(SafeAreaRegions horizontal, SafeAreaRegions vertical)
    public SafeAreaEdges(SafeAreaRegions left, SafeAreaRegions top, SafeAreaRegions right, SafeAreaRegions bottom)
    
    // Static properties
    public static SafeAreaEdges None { get; }
    public static SafeAreaEdges All { get; }
    public static SafeAreaEdges Default { get; }
    
    // Methods
    public SafeAreaRegions GetEdge(int edge)
    public void SetEdge(int edge, SafeAreaRegions value)
}

3. SafeAreaEdges Properties

Available on these controls:

  • Layout.SafeAreaEdges
  • ContentView.SafeAreaEdges
  • ContentPage.SafeAreaEdges
  • Border.SafeAreaEdges
  • ScrollView.SafeAreaEdges

4. XAML TypeConverter

Supports multiple input formats:

  • 1 value: "None" or "All" - applies to all edges
  • 2 values: "All,None" - horizontal,vertical pattern
  • 4 values: "All,None,All,None" - Left,Top,Right,Bottom order

Usage Examples

XAML Usage

<!-- Single value - all edges -->
<Grid SafeAreaEdges="None">

<!-- Two values - horizontal, vertical -->  
<ContentView SafeAreaEdges="All,None">

<!-- Four values - Left, Top, Right, Bottom -->
<VerticalStackLayout SafeAreaEdges="All,None,All,None">

<!-- Mixed behavior -->
<ScrollView SafeAreaEdges="Container,All,Container,SoftInput">

C# Usage

// Constructor patterns
layout.SafeAreaEdges = new SafeAreaEdges(SafeAreaRegions.None);
layout.SafeAreaEdges = new SafeAreaEdges(SafeAreaRegions.All, SafeAreaRegions.None);
layout.SafeAreaEdges = new SafeAreaEdges(
    SafeAreaRegions.All,      // Left
    SafeAreaRegions.None,     // Top  
    SafeAreaRegions.All,      // Right
    SafeAreaRegions.SoftInput // Bottom
);

// Static properties
layout.SafeAreaEdges = SafeAreaEdges.None;
layout.SafeAreaEdges = SafeAreaEdges.All;

// Programmatic edge access
var edges = new SafeAreaEdges();
edges.SetEdge(0, SafeAreaRegions.All);  // Left
edges.SetEdge(1, SafeAreaRegions.None); // Top

Behavior Specification

SafeAreaRegions Behaviors

  • None: Content extends edge-to-edge with no safe area padding
  • SoftInput: Content always pads to avoid keyboard/soft input overlay
  • Container: Content flows under keyboard but avoids status bars, notches, and home indicators
  • Default: Uses platform default safe area behavior
  • All: Content respects all safe area insets (status bars, notches, home indicators, keyboard)

Control-Specific Defaults

  • ContentPage: Returns All when value is Default
  • Layout/ContentView/Border: Returns None when value is Default
  • ScrollView: Returns Default when value is Default (uses iOS ContentInsetAdjustmentBehavior)

Platform Integration

iOS Implementation

  • MauiView.AdjustForSafeAreaPerEdge(): Applies per-edge UIEdgeInsets
  • MauiScrollView: Uses ContentInsetAdjustmentBehavior mapping:
    • All Default edges → .automatic
    • All All edges → .never
    • All None edges → .always
    • Mixed edges → .never with manual ContentInset calculation

Interface Integration

  • ISafeAreaPage: Provides IgnoreSafeAreaForEdge(int edge) and SafeAreaInsets setter
  • ISafeAreaElement: Handles SafeAreaEdges property and fallback logic

Backward Compatibility

  • Existing Layout.IgnoreSafeArea property continues to work unchanged
  • New SafeAreaEdges property provides fallback to legacy behavior when not explicitly set
  • ISafeAreaPage implementations handle both new and legacy APIs seamlessly

Testing Coverage

  • 11 unit tests covering struct behavior, interface implementation, and fallback logic
  • 6 UI test pages for different controls (Layout, ContentView, ContentPage, Border, ScrollView)
  • 6 Appium tests validating interactive behavior and settings persistence

Loading
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-layout StackLayout, GridLayout, ContentView, AbsoluteLayout, FlexLayout, ContentPresenter p/0 Current heighest priority issues that we are targeting for a release.

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

4 participants