iPhone X and safe margins with Xamarin Forms

CarlosCMCarlosCM USMember ✭✭

Hi!

I have finished my app, but I have tested it with the iPhone X simulator and I'm totally out of the safe margins.

I'm searching for info everywhere, but I can't find anything specific to that.

I have alleviated the problem using always a NavigationBar, but the problem still persists if I put the device in landscape mode.

Does someone know how to apply extra margins if necessary with the iPhone X?

Thanks!

Best Answers

  • CarlosCMCarlosCM USMember ✭✭
    Accepted Answer

    Try to call it AFTER base.FinishedLaunching(app, options):

    public override bool FinishedLaunching(UIApplication app, NSDictionary options)
    {
    global::Xamarin.Forms.Forms.Init();
    LoadApplication(new App());
    var result = base.FinishedLaunching(app, options);
    if (UIApplication.SharedApplication.KeyWindow != null)
    {
    Constants.IPhoneXSafeBottom = UIApplication.SharedApplication.KeyWindow.SafeAreaInsets.Bottom;
    }
    return result;
    }

Answers

  • RogerHardimanRogerHardiman GBMember ✭✭

    I looked at this too and got stuck
    I was trying to write some code in AppDelegate.cs but never managed to get any useful information.
    Hoping someone else has a good suggestion.

  • Zeno.FoltinZeno.Foltin USMember

    Seems like it's "coming". Question is when? - forums.xamarin.com / discussion / 104789 - sorry, can't post links yet (WTF?)

  • EddieLudemaEddieLudema USMember ✭✭

    Hi Carlos!

    Thanks for the solution! It seems to be working great in the simulator. Have you been able to test it on a physical iPhone X? When I use...

    var sa = UIApplication.SharedApplication.KeyWindow.SafeAreaInsets

    ... everything is fine in the simulator - returns 0 unless it's an iPhone X... but when I run it on my physical iPhone 7, SafeAreaInsets throws an Objective C exception. I'm just wondering if the physical iPhone X will also not like SafeAreaInsets.....

    Hopefully that made sense!

  • CarlosCMCarlosCM USMember ✭✭

    Hi @EddieLudema! I'm so glad to be of help :)

    I have only tested on the simulator and on a iPod 6.

    About the exception, my guess is that you don't have iOS 11 installed. According the docs, it is only supported +iOS 11.0. Could this be the cause?

  • HcDHcD BEMember ✭✭

    @Zeno.Foltin said:
    Seems like it's "coming". Question is when? - forums.xamarin.com / discussion / 104789 - sorry, can't post links yet (WTF?)

    I've been a member since June 2015 , and still get the "You have to be around a little longer to be able to post links" .. wtf indeed ...

  • HcDHcD BEMember ✭✭

    @Zeno.Foltin said:
    Seems like it's "coming". Question is when? - forums.xamarin.com / discussion / 104789 - sorry, can't post links yet (WTF?)

    I've been a member since June 2015 , and still get the "You have to be around a little longer to be able to post links" .. wtf indeed ...

  • Motoko89Motoko89 USMember ✭✭

    @CarlosCM said:
    Thanks for you answers so far :)

    I made some progress and I found something that is working for me, for now. I just discovered what I am using here, so maybe I'm doing something terribly wrong :)

    I'm doing this in the iOS code (you can use a DependencyService to access from PCL):

    var sa = UIApplication.SharedApplication.KeyWindow.SafeAreaInsets;

    In 'sa' you have the top, left, bottom and right margins, only for iPhone X. For previous iPhones, all fields are always 0 (tested only with simulator). As additional info, I'm using this to get the margins for previous devices:

    var lm = UIApplication.SharedApplication.KeyWindow.RootViewController.SystemMinimumLayoutMargins

    Here you have 'lm.Leading' for what I understand is the top margin and 'lm.Trailing' for what I understand is the bottom margin.

    Anyway, you can apply these values to the layouts of your pages and everything will be inside the safe area.

    Now, you have to refresh the margins when the device is rotated or when the status bar grows or shrinks. I'm using events from the iOS layer (I'm not using the SizeChanged events because if you rotate 180º, the event is not called because the size is exactly the same. Nowadays is not a problem, but I prefer this solution as I feel it is more future proof):

    NSNotificationCenter.DefaultCenter.AddObserver( UIApplication.DidChangeStatusBarOrientationNotification, ( NSNotification n ) => { OnSafeAreaChanged( this, new EventArgs( ) ); } );

    NSNotificationCenter.DefaultCenter.AddObserver( UIApplication.DidChangeStatusBarFrameNotification, ( NSNotification n ) => { OnSafeAreaChanged( this, new EventArgs( ) ); } );

    'OnSafeAreaChanged' is an event of mine. I connect to it from the PCL just to refresh the margins of the affected layouts.

    I hope I'm explaining myself OK... English is not my first language, and besides that, I tend to explain myself so bad :dizzy:

    Hope that helps. I will try to post more details when I know more about the results of doing this that way.

    Hi @CarlosCM , I try to access SafeAreaInsets in FinishedLaunching(UIApplication app, NSDictionary options) but KeyWindow is null, where do you put this code? Thanks,

  • CarlosCMCarlosCM USMember ✭✭

    @Motoko89 hey!

    It has to be called in AppDelegate.FinishedLaunching or after.

  • Motoko89Motoko89 USMember ✭✭
    edited October 31

    @CarlosCM said:
    @Motoko89 hey!

    It has to be called in AppDelegate.FinishedLaunching or after.

    Yes, I used it inside FinishedLaunching but the inside of the if block is never hit
    public override bool FinishedLaunching(UIApplication app, NSDictionary options)
    {
    global::Xamarin.Forms.Forms.Init();
    LoadApplication(new App());
    if (UIApplication.SharedApplication.KeyWindow != null)
    {
    Constants.IPhoneXSafeBottom = UIApplication.SharedApplication.KeyWindow.SafeAreaInsets.Bottom;
    }
    return base.FinishedLaunching(app, options);
    }

  • CarlosCMCarlosCM USMember ✭✭
    Accepted Answer

    Try to call it AFTER base.FinishedLaunching(app, options):

    public override bool FinishedLaunching(UIApplication app, NSDictionary options)
    {
    global::Xamarin.Forms.Forms.Init();
    LoadApplication(new App());
    var result = base.FinishedLaunching(app, options);
    if (UIApplication.SharedApplication.KeyWindow != null)
    {
    Constants.IPhoneXSafeBottom = UIApplication.SharedApplication.KeyWindow.SafeAreaInsets.Bottom;
    }
    return result;
    }

  • rizkyariorizkyario USMember ✭✭

    @CarlosCM Thanks! Calling it after base.FinishedLaunching(app, options); works.

  • SebastianKruseSebastianKruse USMember ✭✭✭
    edited November 5

    @CarlosCM @rizkyario is it normal that I receive Lead and Trail 16 and after a rotation always Lead and Trail 20 (iPhone X Simulator; also if I rotate back to Portrait)?

    And is this correctly assumed?:
    Portrait = Leading means top, Trailing means bottom;
    Upside down = Leading means bottom, Trailing means top;
    Landscape left (notch right?) = Leading means right, Trailing means right;
    Landscape right (notch left?) = Leading means left, Trailing means right;

  • CarlosCMCarlosCM USMember ✭✭

    @SebastianKruse I'm by no means an expert in this regard, by I agree with you.
    @rizkyario so glad! :)

Sign In or Register to comment.