How to allow for iOS status bar and iPhone X notch

2019-03-31 18:51发布

问题:

I'm fairly new to this, so sorry if this is a dumb question. How do I get my Xamarin.Forms app to start below the status bar or the notch when applicable? I've tried using a NavigationPage, but then it started wear below the top of the screen. I've also seen a few other solutions, but I can't make it work. Can anyone help?

Thanks!

回答1:

use UseSafeArea

using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
using Xamarin.Forms;

namespace iPhoneX 
{
    public partial class ItemsPage : ContentPage
    {
        public ItemsPage()
        {
            InitializeComponent();

            On<Xamarin.Forms.PlatformConfiguration.iOS>().SetUseSafeArea(true);
        }
    }
}


回答2:

is it possible to make one thing on the screen expand all the way to the edges?

(from this answer)

Stretching elements out of the bounds of the safe area is arguably a use case in the case you provided. The bar is a mere background element and not content, as the navigation bar is, which also stretches to fill the whole screen.

Having said that, you unfortunately don't get this for free, but have to implement this by yourself. Assume you have the following XAML

<ContentPage ...>
    <StackLayout>
        <ContentView BackgroundColor="LightSkyBlue" HorizontalOptions="Fill" x:Name="Header">
            <!-- Header -->
        </ContentView>
        <ContentView x:Name="Content">
            <!-- Content -->
        </ContentView>
    </StackLayout>
</ContentPage>

In your code-behind (I would not use it like this, but to make the point it suffices. For a real application I have written a utility class, which is attached to the view and manages the insets.) you can now check for the property SafeAreaInsets being changed

class SafeAreaPage : ContentPage
{
    // elided constructor

    protected override void OnPropertyChanged(string propertyName)
    {
        if(propertyName = "SafeAreaInsets")
        {
            var insets = On<Xamarin.Forms.PlatformConfiguration.iOS>.GetSafeAreaInsets();

            var headerInsets = insets; // Thickness is a value type
            headerInsets.Bottom = 0;

            var contentInsets = insets;
            contentInsets.Top = 0;

            Header.Padding = headerInsets;
            Content.Padding = contentInsets;
        }
    }
}

How you set the Paddings of your views depends on your layouts, but this way you have a bit more control on how the safe area insets are used, although it is a bit fiddly.



回答3:

You'll need to consider the safe area but have the background colors expand to take the full screen. So you shouldn't use

On<Xamarin.Forms.PlatformConfiguration.iOS>().SetUseSafeArea(true);

this will box your page with large empty spaces on the bottom and top edges.

Instead, you should measure the safe areas and apply it as padding to your root view.

[assembly: ResolutionGroupName("Enterprise")]
[assembly: ExportEffect(typeof(SafeAreaPaddingEffect), nameof(SafeAreaPaddingEffect))]
namespace Enterprise.iOS.Effects
{
    class SafeAreaPaddingEffect : PlatformEffect
    {
        Thickness _padding;
        protected override void OnAttached()
        {
            if (Element is Layout element)
            {
                if (UIDevice.CurrentDevice.CheckSystemVersion(11, 0))
                {
                    _padding = element.Padding;
                    var insets = UIApplication.SharedApplication.Windows[0].SafeAreaInsets; // Can't use KeyWindow this early
                    if (insets.Top > 0) // We have a notch
                    {
                        element.Padding = new Thickness(_padding.Left + insets.Left, _padding.Top + insets.Top, _padding.Right + insets.Right, _padding.Bottom);
                        return;
                    }
                }
                // Uses a default Padding of 20. Could use an property to modify if you wanted.
                element.Padding = new Thickness(_padding.Left, _padding.Top + 20, _padding.Right, _padding.Bottom);
            }
        }

        protected override void OnDetached()
        {
            if (Element is Layout element)
            {
                element.Padding = _padding;
            }
        }
    }
}

then in xaml:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"                 
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 
             x:Class="Enterprise.View.Features.Authentication.LoginView"                 
             xmlns:effect="clr-namespace:Enterprise.View.Effects">        
    <Grid>                      
        <Grid.RowDefinitions>               
            <RowDefinition Height="100"/>                
            <RowDefinition Height="*" />            
        </Grid.RowDefinitions>            
        <ContentView BackgroundColor="Green">                
            <ContentView.Effects>                    
                <effect:SafeAreaPaddingEffect />                
            </ContentView.Effects>                
            <Label Text="Hello, from XamarinHelp.com" />            
        </ContentView>                    
    </Grid>
</ContentPage>

ref: https://xamarinhelp.com/safeareainsets-xamarin-forms-ios/ Thank Adam, not me!