Is there a way to add an identifier to Auto Layout

2019-01-11 12:49发布

After doing some visual layout in Interface Builder I've created some constraints that I want to access at runtime. Is there a way to label or identify constraints in Interface Builder so they can be looked-up later?

The reason I want to do this is I need to perform some calculation base upon the constraints that are visually specified. I am aware that Apple has provided the Visual Format Language and I could specify the constraints programmatically in a controller. I rather not use this approach so I don't lose the design time feedback of IB.

Edit

Making a referencing outlet did work, but the question still stands.

6条回答
迷人小祖宗
2楼-- · 2019-01-11 13:23

Take the IBOutlet of your auto layout constraint.

There is one property called constant in the NSLayoutConstraint class.

For eg, you've taken the IBOutlet of height constraint of any of the views from your IB, and you want to change it's height programmatically, all you need to do is:

 constraint.constant = isMoreHeight ? height1 : height2;

After doing this, you need to update all other views in the view hierarchy of the superview. To do this you'll need to write below line:

[self setLayoutIfNeeded];

For better user experience, you can put this line inside your animations block for smoother transition effects,

[UIView animateWithDuration:0.3f animations:^{
      [self.view layoutIfNeeded];
}];

Hope this helps..

查看更多
爷、活的狠高调
3楼-- · 2019-01-11 13:33
  1. Since Xcode 7 you can do it in storyboard:

enter image description here

  1. However if you set up your constraint in code, do the following:

    let constraint = NSLayoutConstraint() 
    constraint.identifier = "identifier"
    
  2. For these constraints you have set up in storyboard, but you must set identifier in code:

    for subview in view.subviews {
        for constraint in subview.constraints() {
            constraint.identifier = "identifier"
        }
    }
    
查看更多
贪生不怕死
4楼-- · 2019-01-11 13:34

Also you could link constraint to properties of your controller as you do for any other components. Just ctrl drag it into your code:

enter image description here

And then it will be accessible in code of your controller as property:

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

And you could change it value for example:

self.myConstraint.constant=100.;
查看更多
该账号已被封号
5楼-- · 2019-01-11 13:35

Just adding on to @vacawama's answer. You can write a UIView category and pull out constraints using a simple function, as opposed to copy/pasting loops everywhere you need to find a constraint:

.h file:

#import <UIKit/UIKit.h>

@interface UIView (EasyAutolayout)

-(NSLayoutConstraint *)constraintForIdentifier:(NSString *)identifier;

@end

.m file:

#import "UIView+EasyAutolayout.h"

@implementation UIView (EasyAutolayout)

-(NSLayoutConstraint *)constraintForIdentifier:(NSString *)identifier {

    for (NSLayoutConstraint *constraint in self.constraints) {
        if ([constraint.identifier isEqualToString:identifier]) {
            return constraint;
        }
    }
    return nil;
}

@end
查看更多
祖国的老花朵
6楼-- · 2019-01-11 13:40

Update:

As explained by Bartłomiej Semańczyk in his answer, there is now an Identifier field visible in the Attributes Inspector for the NSLayoutConstraint making it unnecessary to expose this field yourself. Just select the constraint in the Document Outline view or in the Storyboard view and then add an identifier in the Attributes Inspector on the right.


Earlier Answer:

Yes, this can be done. NSLayoutConstraint has a property called identifier than can be exposed in Interface Builder and assigned. To demo this, I created a Single View Application that has a single subview that is a red box. This subview has 4 constraints: width, height, centered horizontally in container, centered vertically in container. I gave the width constraint the identifier redBoxWidth by doing the following:

  1. Click on the width constraint in the Document Layout View. Then in the Identity Inspector under User Defined Runtime Attributes, click on the + under Key Path. Change keyPath to identifier, change the Type Boolean to String, and set the Value to redBoxWidth.

    naming a constraint

  2. Then in ViewDidLoad it is possible to find the constraint by name and change its value:

    class ViewController: UIViewController {
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            for subview in view.subviews as [UIView] {
                for constraint in subview.constraints() as [NSLayoutConstraint] {
                    if constraint.identifier == "redBoxWidth" {
                        constraint.constant = 300
                    }
                }
            }
        }
    }
    
查看更多
在下西门庆
7楼-- · 2019-01-11 13:44

What about this:

if let myconstraint = self.view.constraints.filter( { $0.identifier == "myconstraintId" }).first {
    // TODO: your code here...
}
查看更多
登录 后发表回答