65

Apple's documentation on creating Auto Layout constraints between a view and one of the layout guides only shows an example using VFL.

Is there any way to create these constraints programmatically without VFL (using NSLayoutConstraint's other API or similar)?

(Note: I'm specifically asking about doing this in code, not in Interface Builder. And I don't want the calculated length of the guide set as a static constant on a constraint, I want a constraint where changes to the layout guide length would automatically cause the constrained view to adjust position.)

smileyborg
  • 30,197
  • 11
  • 60
  • 73

4 Answers4

93

For a UIButton that you want to place 20 points below the UIViewController.topLayoutGuide you create the NSLayoutConstraint like so:

[NSLayoutConstraint constraintWithItem:self.button
                             attribute:NSLayoutAttributeTop
                             relatedBy:NSLayoutRelationEqual
                                toItem:self.topLayoutGuide
                             attribute:NSLayoutAttributeBottom
                            multiplier:1.0
                              constant:20.0];

With iOS 9 you can also create the NSLayoutConstraint this way:

[self.button.topAnchor constraintEqualToAnchor:self.topLayoutGuide.bottomAnchor
                                      constant:20.0];
Jamie McDaniel
  • 1,809
  • 19
  • 15
  • 9
    You're (half?) right. Your code does work, but `NSLayoutAttributeBaseline` is not required to get it to work. If you're pinning to the `topLayoutGuide`, `NSLayoutAttributeBottom` works the same (and `NSLayoutAttributeTop` should be used when pinning to the `bottomLayoutGuide` of course). Anyways...I thought I tried this approach before and it didn't work...guess I screwed something up. – smileyborg Nov 15 '13 at 06:26
  • Thanks @smileyborg. I also updated my answer to include the new iOS 9 API. – Jamie McDaniel Jan 13 '16 at 19:13
6

To supplement @JamieMcDaniel's answer, the Swift + iOS9 version would be:

self.button.topAnchor
    .constraintEqualToAnchor( self.topLayoutGuide.bottomAnchor ).active = true

Don't forget the .active = true part as otherwise the constraint doesn't kick in automatically.

0x6A75616E
  • 4,696
  • 2
  • 33
  • 57
3

This is a gist I've created, you are supposed to embed all your subviews into a tank view(container view) added into a xib, it removes tank view-superview xib constraints and adds an upper constraints to topLayoutGuide giving an iOS6 look. It could be interesting for what you want to achieve.

//This should be added before the layout of the view
- (void) adaptToTopLayoutGuide {
    //Check if we can get the top layoutguide
    if (![self respondsToSelector:@selector(topLayoutGuide)]) {
        return;
    }
    //tankView is a contaner view
    NSArray * array = [self.tankView referencingConstraintsInSuperviews]; //<--For this method get the Autolayout Demistified Book Sample made by Erica Sadun
    [self.view removeConstraints:array];
    NSArray * constraintsVertical = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|[topLayoutGuide]-0-[tankView]|" options:0 metrics:nil views:@{@"tankView": self.tankView, @"topLayoutGuide":self.topLayoutGuide}];
    [self.view addConstraints:constraintsVertical];
    NSArray * constraintsHorizontal = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[tankView]|" options:0 metrics:nil views:@{@"tankView": self.tankView}];
    [self.view addConstraints:constraintsHorizontal];

}
Andrea
  • 26,120
  • 10
  • 85
  • 131
  • Sorry, but this doesn't address my specific question. – smileyborg Oct 04 '13 at 17:09
  • 1
    VLF is the way to go with autolayout, I can't find any specific reason for not using it, I've just suggested a piece of code that could help you to point into the right direction.. If you want to think about it. – Andrea Oct 04 '13 at 18:28
  • 2
    VFL has it's own set of pros and cons. I am personally not a big fan of it, that's why I wrote [this Auto Layout category on UIView](https://github.com/smileyborg/UIView-AutoLayout) which solves even more use cases than VFL can. I've even written some pros/cons of all the Auto Layout approaches (including VFL) on the README of that project. – smileyborg Oct 04 '13 at 18:48
  • Really interesting... I've read the readme and I agree with your points, the thing that I'm missing is the Use case, I mean why use normal layout for general purpose layouting, instead of VLF?, performance?or something else? – Andrea Oct 04 '13 at 20:15
  • What do you mean by "normal layout"? – smileyborg Oct 04 '13 at 20:20
  • I mean create each single constraint programmatically without using VLF, until now I've never found it limiting in general use. I'm just curious why would someone use single constraint instead of VLF, I understand that maybe there are exceptions about sort of particular layouting. Is there a performace reason? – Andrea Oct 05 '13 at 07:44
  • Take a look at the what the auto layout code looks like in the example project on GitHub. In my opinion, it's nicer to read & write than VFL (less crazy syntax, more Obj-C like). It's not about performance at all. But it is about compiler checking, easier debugging (knowing exactly what each line is doing), and easier learning curve among other things. – smileyborg Oct 05 '13 at 07:49
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/38655/discussion-between-smileyborg-and-andrea) – smileyborg Oct 05 '13 at 07:49
  • Andrea, it's a shame you got negative points for a *correct answer* that is even really useful! Both VFL and `constraintWithItem` methods are right, it's just a matter of taste. I prefer VFL whenever possible, I just miss some features like centering. To cut some code I created a really simple [Autolayout helper](https://github.com/fmaylinch/autolayout-helper), just in case you find it useful. – Ferran Maylinch May 21 '15 at 17:42
  • I'd suggest to change the vertical constraint(s) from `@"V:|[topLayoutGuide]-0-[tankView]|"` to `@"V:[topLayoutGuide][tankView]|"` (removed the relation between the top of the superview and the top layout guide and the `-0-` between the top layout guide and tankView)... – Michael Kessler Feb 11 '16 at 20:23
3

Just an addition to @Jamie McDaniel, in case it's not immediately obvious, you need to add the constraint that he suggests to create:

NSLayoutConstraint *buttonTopConstraint = [NSLayoutConstraint constraintWithItem:self.button
                                 attribute:NSLayoutAttributeTop
                                 relatedBy:NSLayoutRelationEqual
                                    toItem:self.topLayoutGuide
                                 attribute:NSLayoutAttributeBottom
                                multiplier:1.0
                                  constant:20.0];
[self.view addConstraint:buttonTopConstraint];
Alex Y
  • 61
  • 1