17

I have just changed my app from supporting iOS 8 and up to supporting iOS 9 and up.

Since I don't use storyboards to create my views, I was wondering if there's the "Use Safe Area Guides" option programmatically or something like that.

I've tried to anchor my view but they keep overlapping the top & bottom in the iPhone X simulator.

Krunal
  • 77,632
  • 48
  • 245
  • 261
Ravindhiran
  • 5,304
  • 9
  • 50
  • 82

2 Answers2

34

Try this in Objective-C and see:

UIView * myView = // initialize view using IBOutlet or programtically

myView.backgroundColor = [UIColor redColor];
myView.translatesAutoresizingMaskIntoConstraints = NO;

if (@available(iOS 11, *)) {
    UILayoutGuide * guide = self.view.safeAreaLayoutGuide;
    [myView.leadingAnchor constraintEqualToAnchor:guide.leadingAnchor].active = YES;
    [myView.trailingAnchor constraintEqualToAnchor:guide.trailingAnchor].active = YES;
    [myView.topAnchor constraintEqualToAnchor:guide.topAnchor].active = YES;
    [myView.bottomAnchor constraintEqualToAnchor:guide.bottomAnchor].active = YES;
} else {
    UILayoutGuide *margins = self.view.layoutMarginsGuide;
    [myView.leadingAnchor constraintEqualToAnchor:margins.leadingAnchor].active = YES;
    [myView.trailingAnchor constraintEqualToAnchor:margins.trailingAnchor].active = YES;
    [myView.topAnchor constraintEqualToAnchor:self.topLayoutGuide.bottomAnchor].active = YES;
    [myView.bottomAnchor constraintEqualToAnchor:self.bottomLayoutGuide.topAnchor].active = YES;

}

// Refresh myView and/or main view
[self.view layoutIfNeeded];
//[self.myView layoutIfNeeded];

Ref from: Use Safe Area Layout programmatically - Swift

Result:

enter image description here

Krunal
  • 77,632
  • 48
  • 245
  • 261
  • May I know how can I modify and use your code if I want to apply safe area layout constraints to custom tabBar controller and that to programatically? – Paras Gorasiya Nov 13 '17 at 05:19
  • `safeAreaLayoutGuide` is available only since iOS 11. Before iOS 11 you can use `topLayoutGuide` or `bottomLayoutGuide`. (Or use Xibs\storyboards) – DanSkeel Dec 19 '17 at 16:19
  • @Krunal you can’t do that if your deployment Target is less than iOS 11. For iOS less than 11, you can use safeArea in storyboard but not in code (`safeAreaLayoutGuide`) – DanSkeel Dec 20 '17 at 15:24
  • 1
    @DanSkeel - Agree with you. Updated it now. You are welcomed to improve this answer by adding your input. – Krunal Dec 20 '17 at 16:35
  • 1
    Hi @Krunal! Thanks for this! How about if I want to add a constant? – KarenAnne Apr 30 '18 at 09:57
  • @KarenAnne - It's little tough process to deal with constant in SafeAreaLayout. Please raise/post your question with exact problem statement and solution you are looking for. i'll surely help you there. – Krunal Apr 30 '18 at 09:59
15

You can find top and bottom padding programmatically. I think this will solve your issue.

if (@available(iOS 11.0, *)) {
        UIWindow *window = UIApplication.sharedApplication.keyWindow;
        CGFloat topPadding = window.safeAreaInsets.top;
        CGFloat bottomPadding = window.safeAreaInsets.bottom;
}

Edit: As mentioned in the comments (thanks, @albert-renshaw), the object can't be drawn from viewDidLoad on the first run as UIWindow won't be accessible until after at least one run loop. To bypass this you can do it several ways:

1. Simply move your viewDidLoad code into a new method postViewDidLoad and use:

[self performSelector:@selector(postViewDidLoad) withObject:nil afterDelay:0.0f];

...in the original viewDidLoad method, then UIWindow will be accessible.

OR

2. Enclose creation of your object in

dispatch_async(dispatch_get_main_queue(), ^{
// your code here...
});
Repose
  • 2,157
  • 1
  • 24
  • 26
user6788419
  • 7,196
  • 1
  • 16
  • 28
  • 2
    The question is related to Objective C not swift. Edit it before someone down votes you. – Pranjal Bikash Das Nov 02 '17 at 13:18
  • 1
    Language doesn't matter. This is very bad example. – Damian Rzeszot Nov 02 '17 at 15:57
  • 5
    @PranjalBikashDas this is objective C not swift – user6788419 Nov 03 '17 at 04:50
  • @DamianRzeszot please explain what is the wrong with this answer – user6788419 Nov 03 '17 at 13:36
  • Arundas you'll take all those values and then what? create constraints from view to superview with constants = those values? makes no sense of safe area layout guides existence. @Krunal gave good solution for this problem. – Damian Rzeszot Nov 05 '17 at 22:38
  • @DamianRzeszot Can u explain what are the issues are facing while using this way. I use this way in my project. If you do i can change it from my project. – user6788419 Nov 06 '17 at 09:58
  • @Arundas This works for me! Thank you very much! I vote for you . – Ted Yu Nov 20 '17 at 07:50
  • @user871221 Happy to hear it helped u – user6788419 Nov 20 '17 at 08:00
  • 2
    If you don't use AutoLayout or Storyboards this is the way to go. – Reuben Scratton Jan 16 '18 at 18:26
  • 1
    This is super useful to the views created with frames instead of the constraints, where you will get the padding for safe area if needed. so the padding will be either 0 or 34 for example. – AaoIi Feb 16 '18 at 15:51
  • 1
    Note: Can't call this in viewDidLoad of your main ViewController, as UIWindow won't be accessible until after at least one run loop. To bypass you can simply move your viewDidLoad code into a new method `postViewDidLoad` and use `[self performSelector:@selector(postViewDidLoad) afterDelay:0.0f];` in the original viewDidLoad method, then UIWindow will be accessible and this will work. – Albert Renshaw Jun 23 '18 at 01:35