NSLayoutConstraint between Navigation Bar & ViewControllers View

11,989

Solution 1

Yes you can add a constraint between the Navigation Bar and a view. Your root view conroller added to the navigation controller contains topLayoutGuide. so adjust your code like this:

NSLayoutConstraint* cn = [NSLayoutConstraint constraintWithItem:_textField
                                                      attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual
                                                         toItem:self.rootViewController.topLayoutGuide attribute:NSLayoutAttributeBottom
                                                     multiplier:1.0 constant:20];
[self.rootViewController.view addConstraint:cn];

notice that i'm not referencing the navigation controller at all but the rootViewController of the navigation Controller.

Also you can use bottomLayoutGuide to go above the TabBar the same way. (however if you need to do that you'll run into a bug in iOS frameworks with a workaround patch here: UIViews ending up beneath tab bar )

Solution 2

Check out the topLayoutGuide property on UIViewController.

There's an example in Apple's doc for `UIViewController' that goes like this...

topLayoutGuide
Indicates the highest vertical extent for your onscreen content, for use with Auto Layout constraints. (read-only)

@property(nonatomic, readonly, retain) id<UILayoutSupport> topLayoutGuide

And then...

As an example of how to programmatically use this property with Auto Layout, say you want to position a control such that its top edge is 20 points below the top layout guide. This scenario applies to any of the scenarios listed above. Use code similar to the following:

[button setTranslatesAutoresizingMaskIntoConstraints: NO];
id topGuide = myViewController.topLayoutGuide;
NSDictionary *viewsDictionary = NSDictionaryOfVariableBindings (button, topGuide);
[myViewController.view addConstraints:
    [NSLayoutConstraint constraintsWithVisualFormat: @"V: [topGuide]-20-[button]"
                                                 options: 0
                                                 metrics: nil
                                                   views: viewsDictionary]
self.view layoutSubviews; // You must call this method here or the system raises an exception
];

Solution 3

Add the constraint between the top of the textField and the top of the parent view. The constant for the constraint can be set to the height of the status bar + height of the navigation bar.

Obviously, the following code snippet will only work if both the Status Bar and Navigation Bar are translucent and the view controller wants full screen layout. You can easily test for transparency and adjust accordingly, if necessary.

If you're using interface builder, you can also create an IBOutlet for the existing constraint and just set it's constant rather than creating a new constraint.

// Obtain the view rect of the status bar frame in either portrait or landscape
CGRect statusBarFrame = [[UIApplication sharedApplication] statusBarFrame];
CGRect statusBarWindowRect = [self.view.window convertRect:statusBarFrame fromWindow: nil];
CGRect statusBarViewRect = [self.view convertRect:statusBarWindowRect fromView: nil];

// Add Status Bar and Navigation Bar heights together
CGFloat height = self.navigationController.navigationBar.frame.size.height +
statusBarViewRect.size.height;

// Create & Add Constraint
NSLayoutConstraint *constraint =
[NSLayoutConstraint constraintWithItem:self.fieldLabel
                             attribute:NSLayoutAttributeTop
                             relatedBy:0
                                toItem:self.view
                             attribute:NSLayoutAttributeTop
                            multiplier:1
                              constant:height];

[self.view addConstraint:constraint];
Share:
11,989
Sj.
Author by

Sj.

Updated on June 17, 2022

Comments

  • Sj.
    Sj. almost 2 years

    Can we add a NSLayoutConstraint between self.navigationcontroller.navigationbar and a view inside the self.view. Here self is a UIViewController instance and _textField is a subview of self.view

    What I need is that the UI should look alike irrespective whether the navigationBar is Translucent or not.

    I've tried the following. But It does not work.

    NSLayoutConstraint* cn = [NSLayoutConstraint constraintWithItem:_textField
                                                          attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual
                                                             toItem:self.navigationController.navigationBar attribute:NSLayoutAttributeBottom
                                                         multiplier:1.0 constant:20];
    [self.navigationcontroller.view addConstraint:cn];