Search code examples
iosxcodeautolayoutsafearealayoutguide

Position a view relative to the bottom of the safe area programmatically


I have a view that pops up from the bottom of the screen, and is loaded in my app delegate. The problem I am having is that I cannot set the y coordinate of the view so it will appear in the same position on all screen sizes. In my case, I am trying to get this popup view to appear just above the tab bar at the bottom of the screen.

This is my code, where I am placing the view relative to [[UIScreen mainScreen] bounds], but it is not consistent across all screen sizes. How can I get the coordinate I need so I can position this view in the same spot vertically on all screens?

    CGRect screenRect = [[UIScreen mainScreen] bounds];
    CGFloat screenWidth = screenRect.size.width;
    float y = [UIScreen mainScreen].bounds.size.height;

    UIInterfaceOrientation deviceOrientation = [[UIApplication sharedApplication] statusBarOrientation];
    if (UIInterfaceOrientationIsLandscape(deviceOrientation))
    {
        [UIView animateWithDuration:0.5
                              delay:.25
                            options: UIViewAnimationOptionCurveEaseOut
                         animations:^{
                             self->popcontroller.frame = CGRectMake(0,y -90, screenWidth, 40);
                         }
                         completion:^(BOOL finished){
                         }];
    }
    else{
        [UIView animateWithDuration:0.5
                              delay:.25
                            options: UIViewAnimationOptionCurveEaseOut
                         animations:^{
                             self->popcontroller.frame = CGRectMake(0,y -120, screenWidth, 40);
                         }
                         completion:^(BOOL finished){
                         }];
    }

    brsAppDelegate *appDelegate = (brsAppDelegate *)[[UIApplication sharedApplication] delegate];
    if (![[appDelegate window].subviews containsObject:popcontroller])
    {  [[appDelegate window] addSubview:popcontroller];

    [popcontroller setNeedsDisplay];
    }
});

}


Solution

  • So in order to detect the extra spacing for the edge insets, there is a property on all views called safeAreaInsets. This can be used to detect if you need to add extra value to the layout params (top/bottom or left/right).

    So in order to get your "extra margins", you can check the top/bottom value of that inset if the app is in portrait, or the "left/right" value of the insets if the app is in landscape.

    One thing to be careful with, this safeAreaInset is set by default on the controller's root view, so if you have a custom view added as a subview, that custom view most likely won't have this property set correctly.

    And to be more specific, in your case, the "frame" code would look something like

    if deviceIsInPortrait {
       let frame = CGRect(x:thisX,
                          y: -90 - self.view.safeAreaInsets.top // this will be 0 for non "notch" phones
                          width: myWidth
                          height: myHeight
    }
    else {
      let frame = CGRect(x:thisX,
                          y: -90 - self.view.safeAreaInsets.left // this will be 0 for non "notch" phones
                          width: myWidth
                          height: myHeight
    }
    

    Also one more piece of advice, use auto-layout as often as possible.