NSLayoutConstraint between Navigation Bar & ViewControllers View
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];
Sj.
Updated on June 17, 2022Comments
-
Sj. almost 2 years
Can we add a
NSLayoutConstraint
betweenself.navigationcontroller.navigationbar
and a view inside theself.view
. Here self is aUIViewController
instance and_textField
is a subview ofself.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];