What's a consistent way to get the safe area insets for the iPhone X in Xamarin.Forms
Asked Answered
S

2

9

I am currently updating some views for the iPhone X. According to this blog post it should be fairly streight-forward, but - like always - it's not as smooth as it's supposed to be.

If you are using the recommended way

public MyView()
{
    InitializeComponent();

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

the items of the View are given a Margin according to the safe area insets, but this applies to views like SearchBar, too, which already adapt to the insets out of the box. Using the code above will result in the gray background of the search bar not taking the whole width, which looks quite strange.

Fortunately the On<iOS> has an extension method SafeAreaInsets() which returns the correct insets - under certain conditions - which one for example can assign to a BindableProperty. Unfortunately the conditions under which we can obtain the insets are not very consistent.

  • When OnSizeAllocated is called the first time, SafeAreaInsets() will return 0,0,0,0
  • When the view is shown SafeAreaInsets() returns the correct value (in OnAppearing)
  • OnSizeAllocated is called multiply after rotation
    • The first time SafeAreaInsets() returns the correct value
    • The second time SafeAreaInsets() returns 0,0,0,0

My current working solution is, to override both and only set my bindable property (which is bound to my views) if the Thickness returned by SafeAreaInsets() is not default(Thickness).

I'd like to know if there is a standard way to always get the correct insets, without having to check if the insets have a sound value.

Subchloride answered 5/12, 2017 at 6:8 Comment(2)
Have you found a solution?Threemaster
It would be worth mentioning which version of Xamarin.Forms you are using, in case it is/was a bug.Loraine
E
6

I did a bit of research on this. Here's couple of my thoughts:

  1. You could actually set the UseSafeArea in XAML (docs) - that's just FYI

  2. The setting of the SafeArea happens when using this extension method, which basically sets the SafeAreaInsetsPropertyKey property and then the page Padding is updated in the UpdatePadding method. The question here is, what calls that extension method and sets it then? I checked the Xamarin.Forms github repo and the answer is simple. It gets called from the PageRenderer, when the ViewSafeAreaInsetsDidChange is called by the iOS. Which means that you don't know exactly when iOS decides to inform you about the current SafeArea - the issues that you're seeing with different values of the inset at different times.

I know it's definitely not what anyone wants but you could override the default iOS PageRenderer and hook up to the ViewSafeAreaInsetsDidChange override. Once it's called you could be 100% sure that you have current SafeArea inset value.

Exsanguine answered 21/8, 2018 at 1:36 Comment(1)
Thank you very much for your answer, but it's not 100% what I need. I am rather looking at edge cases I have to handle.Subchloride
F
0

I used a subscription to change the property value SafeAreaInsets. This complemented the incorrect solution with OnSizeAllocated.

public bool WasAppeared { get; private set; }

public CustomContentPage() : base()
{
    if (Device.RuntimePlatform == Device.iOS)
        PropertyChanged += CustomContentPage_PropertyChanged;
}

protected override void OnAppearing()
{
    base.OnAppearing();

    WasAppeared = true;

    SetSafeArea();
}

protected override void OnDisappearing()
{
    WasAppeared = false;

    base.OnDisappearing();
}

private void CustomContentPage_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
    if (!WasAppeared)
        return;

    if (e.PropertyName == "SafeAreaInsets")
        SetSafeArea();
}

protected void SetSafeArea()
{
    if (Device.RuntimePlatform != Device.iOS)
        return;
}
Fulgurous answered 18/5, 2020 at 11:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.