Resize current view using NSLayoutConstraints

浪子不回头ぞ 提交于 2019-12-08 03:22:36

问题


I'm trying to set the layout of a view using NSLayoutConstraints.

I can set things up within the view correctly, but I also need to be able to resize the current view (the one that I'm setting the constraints for) if the constraints require it. In other words, I want to set a fixed content size with a flexible window, rather than the reverse.

So basically, I have:

NSDictionary *views = [NSDictionary dictionaryWithObjectsAndKeys:self.v1, @"v1",
                       self.v2, @"v2",
                       nil];
// Set horizontal constraints
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"|-[v1]-|"
                                                             options:0
                                                             metrics:nil
                                                               views:views]];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"|-[v2]-|"
                                                             options:0
                                                             metrics:nil
                                                               views:views]];
// Set vertical constraints
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[v1]-[v2]-|"
                                                             options:0
                                                             metrics:nil
                                                               views:views]];
// Initialise height constraint for v1
self.v1Height = [NSLayoutConstraint constraintWithItem:self.v1
                                                attribute:NSLayoutAttributeHeight
                                                relatedBy:NSLayoutRelationEqual
                                                   toItem:nil
                                                attribute:NSLayoutAttributeNotAnAttribute
                                               multiplier:1
                                                 constant:50];

If I later change self.v1Height (by removing it, recreating it, and then readding it), I would like the frame of self to expand (or contract) to accommodate the changed height.

I'm not sure if it's relevant (as I'm more familiar with iOS than OS X), but this is the content view of a NSPopover.

What constraint do I need to add to achieve this?


回答1:


There are a couple of issues:

  1. If you want your constraints to define the size of their containing view, they can't be ambiguous, as they are now. They have to fully define the space they need. For example:

    NSDictionary *views = @{@"v1" : self.v1,
                            @"v2" : self.v2};
    
    // Set horizontal constraints
    
    [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"|-[v1(200)]-|"  options:0 metrics:nil views:views]];
    [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"|-[v2(==v1)]-|" options:0 metrics:nil views:views]];
    
    // Set vertical constraints
    
    [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[v1]-[v2(600)]-|" options:0 metrics:nil views:views]];
    
    // Initialise height constraint for v1
    
    self.v1Height = [NSLayoutConstraint constraintWithItem:self.v1
                                                 attribute:NSLayoutAttributeHeight
                                                 relatedBy:NSLayoutRelationEqual
                                                    toItem:nil
                                                 attribute:NSLayoutAttributeNotAnAttribute
                                                multiplier:1
                                                  constant:50];
    [self addConstraint:self.v1Height];
    

    Note, I'm setting the width of v1, I'm setting v2 to be the same width as v1, and I'm setting the height of v2, also. That, combined with your subsequent creation of the v1Height constraint, now makes the view's layout unambiguous.

  2. Having done that, you also need to tell your view controller to inform the popover controller of its content size when the autolayout has been applied. Thus, your view controller could implement a viewDidLayoutSubviews:

    - (void)viewDidLayoutSubviews
    {
        [super viewDidLayoutSubviews];
    
        self.view.frame = CGRectMake(0.0, 0.0, self.view.frame.size.width, self.view.frame.size.height);
        self.contentSizeForViewInPopover = self.view.frame.size;
    }
    

    Note, that setting of the frame is very curious, but if you don't reset the origin to {0.0, 0.0}, your controls won't appear in the right place. It doesn't seem right that you have to do that, but in my experience, you do.

  3. Somewhat unrelated to your problem, you mention that you're removing v1Height "by removing it, recreating it, and then readding it". That's unnecessary and not recommended. The constant property is modifiable. As the docs say

    "Unlike the other properties, the constant may be modified after constraint creation. Setting the constant on an existing constraint performs much better than removing the constraint and adding a new one that's just like the old but for having a new constant."

    Thus, that means that you can do something as simple as:

    self.v1Height.constant = newHeight;
    [UIView animateWithDuration:0.5
                     animations:^{
                         [self layoutIfNeeded];
                     }];
    



回答2:


As it turns out, NSPopoverController is an exception to the rule, and translatesAutoresizingMaskIntoConstraints must be YES for autolayout to work correctly.




回答3:


Better later than never...

For Storyboard, IB and Swift:

Just control-drag your constraint like any other control to your viewController

@IBOutlet weak var spaceToTopThatIDecided: NSLayoutConstraint!

then change it simply:

spaceToTopThatIDecided.constant = 44

That's all!




回答4:


I found a easy solution to update constraints (resize ) with a category:

Hide autolayout UIView : How to get existing NSLayoutConstraint to update this one



来源:https://stackoverflow.com/questions/17130136/resize-current-view-using-nslayoutconstraints

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!