Is there any way to add constraint between a view and the top layout guide in a xib file?

46,911

Solution 1

You should refer the following example, this will definitely help you for your problem. I got this from http://developer.apple.com .

[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]
];

Solution 2

Here is my alternative solution.

Find a UIView as a pivot, set its top layout constraint a fixed vertical space to container's top.

Control-Drag this layout constraint as an IBOutlet, such as

@property (weak, nonatomic) IBOutlet NSLayoutConstraint *topLayoutConstraint;

Finally, just override viewWillLayoutSubviews method of UIViewController like following

- (void)viewWillLayoutSubviews
{
    [super viewWillLayoutSubviews];

    self.topLayoutConstraint.constant = [self.topLayoutGuide length] + YOUR_TOP_CONSTRSINT;
}

All the other views' top constraint are based this pivot view, all done :)

Solution 3

From iOS 9 you can also do it more simple with topLayoutGuide's anchors:

  • Swift 3

view.topAnchor.constraint(equalTo: self.topLayoutGuide.bottomAnchor).isActive = true

  • ObjC

[controller.view.topAnchor constraintEqualToAnchor:controller.topLayoutGuide.bottomAnchor].active = YES;

Solution 4

Until now even using XCode 6 I cannot align controls to top layout guide on .xib files. Instead, I am using an alternative way.

First, on interface builder, I still align controls to top border of viewcontroler's view.

Then, in viewDidLoad method, I replace some constraints so they will align to top layout guide instead of main view:

- (void)viewDidLoad
{
    [super viewDidLoad];

    NSArray *constraints = self.view.constraints;
    for (NSLayoutConstraint *constraint in constraints) {
        if ( (constraint.firstItem == self.view) && (constraint.firstAttribute == NSLayoutAttributeTop) ) {
            NSLayoutConstraint *newConstraint = [self constraint:constraint replaceFirstItemBy:self.topLayoutGuide attribute:NSLayoutAttributeBottom];
            [self.view removeConstraint:constraint];
            [self.view addConstraint:newConstraint];
        } else if ( (constraint.secondItem == self.view) && (constraint.secondAttribute == NSLayoutAttributeTop) ) {
            NSLayoutConstraint *newConstraint = [self constraint:constraint replaceSecondItemBy:self.topLayoutGuide attribute:NSLayoutAttributeBottom];
            [self.view removeConstraint:constraint];
            [self.view addConstraint:newConstraint];
        }
    }
}

- (NSLayoutConstraint*)constraint:(NSLayoutConstraint*)constraint replaceFirstItemBy:(id)newItem attribute:(NSLayoutAttribute)newAttribute {
    UILayoutPriority priority = constraint.priority;
    NSLayoutRelation relation = constraint.relation;
    id secondItem = constraint.secondItem;
    NSLayoutAttribute secondAttribute = constraint.secondAttribute;
    CGFloat multiplier = constraint.multiplier;
    CGFloat constant = constraint.constant;

    NSLayoutConstraint *newConstraint = [NSLayoutConstraint constraintWithItem:newItem attribute:newAttribute relatedBy:relation toItem:secondItem attribute:secondAttribute multiplier:multiplier constant:constant];
    newConstraint.priority = priority;
    return newConstraint;
}

- (NSLayoutConstraint*)constraint:(NSLayoutConstraint*)constraint replaceSecondItemBy:(id)newItem attribute:(NSLayoutAttribute)newAttribute {
    UILayoutPriority priority = constraint.priority;
    id firstItem = constraint.firstItem;
    NSLayoutAttribute firstAttribute = constraint.firstAttribute;
    NSLayoutRelation relation = constraint.relation;
    CGFloat multiplier = constraint.multiplier;
    CGFloat constant = constraint.constant;

    NSLayoutConstraint *newConstraint = [NSLayoutConstraint constraintWithItem:firstItem attribute:firstAttribute relatedBy:relation toItem:newItem attribute:newAttribute multiplier:multiplier constant:constant];
    newConstraint.priority = priority;
    return newConstraint;
}

Think this is not the best way because we replace objects that we define on interface builder. But it may be an alternative way that we can think about.

Solution 5

Of course, You can not only add constraint between a view and the top layout guide or bottom layout guide by programmatically but also you can remove and access constraint between a view and the top and bottom layout guide with the help of KVConstraintExtensionsMaster library.

// create containerView
UIView *containerView = [UIView prepareNewViewForAutoLayout];
[containerView setBackgroundColor:[UIColor brownColor]];
[self.view addSubview:containerView];

// To add Top and Bottom Layout Guide constraint of containerView
[self applyTopLayoutGuideConstraintToView:containerView withPadding:0];
[self applyBottomLayoutGuideConstraintToView:containerView withPadding:50];

// To access top Layout Guide Constraint and update it's constant value.
NSLayoutConstraint *topLayoutGuideConstraint = [self accessAppliedTopLayoutGuideConstraintFromView:containerView];
topLayoutGuideConstraint.constant = 50;

// To access bottom Layout Guide Constraint and update it's constant value with animation
NSLayoutConstraint *bottomLayoutGuideConstraint = [self accessAppliedBottomLayoutGuideConstraintFromView:containerView];
bottomLayoutGuideConstraint.constant = 80;
[self.view updateModifyConstraintsWithAnimation:NULL]; // call this for animation

// To remove Top and Bottom Layout Guide constraint of containerView
[self removeAppliedTopLayoutGuideConstraintFromView:containerView];
[self removeAppliedBottomLayoutGuideConstraintFromView:containerView ];
Share:
46,911
Henry H Miao
Author by

Henry H Miao

Senior full-stack developer at Isobar Australia

Updated on July 05, 2022

Comments

  • Henry H Miao
    Henry H Miao almost 2 years

    In iOS 7, we can now add a constraint between a view and the top layout guide, which I think is very useful to solve the status bar offset issue in iOS7(especially when there is no navigation bar in the view).

    In a storyboard file, I can add this kind of constraints easily. Just hold the control key then drag the view to the container, it will show the "Top Space to Top Layout Guide" option.

    enter image description here

    But when I do the same operation in a xib file, this option disappears.

    enter image description here

    So, is there any way to add this kind of constraints in xib files? Or do I have to add them with code?

  • Nuzhat Zari
    Nuzhat Zari over 10 years
    I have a UIView added to view controller's view and I want in case of iOS7 it should start from 20 and for iOS6 it should start from 0. I am using above code(in place of button I am using my view) but it is not working can know how to resolve this?
  • joslinm
    joslinm over 10 years
    @NuzhatZari you can explicitly check for system version here stackoverflow.com/questions/7848766/…
  • Ricardo Sanchez-Saez
    Ricardo Sanchez-Saez almost 10 years
    It would be nice if these constraints could be set on Xcode for XIBs as well... Xcode should just supply it (regardless of knowledge of the view controller hierarchy).
  • User123335511231
    User123335511231 over 8 years
    Is there a way to layout all the VC's subviews under the status bar, whithout constraints? Like using top layout guide in storyboards?
  • anonymouse
    anonymouse about 8 years
    This won't deal well with the topLayoutGuide moving (say the user is on a call or using GPS or something else causes the topLayoutGuide to increase)
  • CIFilter
    CIFilter over 7 years
    That shouldn't matter. That's the whole point of those guides. You just align to them, and if that VC is inside a navigation controller, it has a certain top layout guide size. If it's presented as a modal VC with no status bar visible, then its size is 0, etc. The VC can and should be able to lay out relative to its guides without knowing what their size is (at design time).
  • Kappe
    Kappe almost 7 years
    best solution by far!