Objective c 使用NSLayoutConstraints调整当前视图的大小

Objective c 使用NSLayoutConstraints调整当前视图的大小,objective-c,cocoa,autolayout,nslayoutconstraint,Objective C,Cocoa,Autolayout,Nslayoutconstraint,我正在尝试使用NSLayoutConstraints设置视图的布局 我可以在视图中正确设置内容,但如果约束需要,我还需要能够调整当前视图(我正在为其设置约束的视图)的大小。换句话说,我想用一个灵活的窗口设置一个固定的内容大小,而不是相反 基本上,我有: NSDictionary *views = [NSDictionary dictionaryWithObjectsAndKeys:self.v1, @"v1", self.v2, @"v2",

我正在尝试使用
NSLayoutConstraint
s设置视图的布局

我可以在视图中正确设置内容,但如果约束需要,我还需要能够调整当前视图(我正在为其设置约束的视图)的大小。换句话说,我想用一个灵活的窗口设置一个固定的内容大小,而不是相反

基本上,我有:

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];
如果我以后更改了
self.v1Height
(通过删除它、重新创建它,然后读取它),我希望
self
的框架能够扩展(或收缩)以适应更改的高度

我不确定它是否相关(因为我对iOS比OSX更熟悉),但这是
nspover
的内容视图


要实现这一点,我需要添加什么约束条件?

有几个问题:

  • 如果希望约束定义其包含视图的大小,它们不能像现在这样模棱两可。他们必须完全定义他们需要的空间。例如:

    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];
    
    注意,我正在设置
    v1
    的宽度,我正在将
    v2
    设置为与
    v1
    相同的宽度,我还在设置
    v2
    的高度。这与随后创建的
    v1Height
    约束相结合,现在可以使视图的布局更加清晰

  • 完成此操作后,还需要告诉视图控制器在应用自动布局时通知popover控制器其内容大小。因此,视图控制器可以实现一个
    viewdilayoutsubviews

    - (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;
    }
    
    请注意,
    帧的设置非常奇怪,但是如果不将原点重置为
    {0.0,0.0}
    ,控件将不会出现在正确的位置。你非得这么做似乎不对,但根据我的经验,你是这样做的

  • 与您的问题有些无关,您提到您正在通过“删除、重新创建、然后读取”来删除
    v1Height
    。这是不必要的,不推荐。
    常量
    属性是可修改的。作为

    “与其他属性不同,
    常量
    可以在创建约束后进行修改。在现有约束上设置
    常量
    比删除约束并添加一个与旧约束相同但具有新的
    常量
    的新约束执行得更好。”

    因此,这意味着你可以做一些简单的事情:

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

  • 事实证明,
    nspovercontroller
    是该规则的一个例外,而
    translatesAutoResizengMackintoConstraints
    必须是
    YES
    才能使autolayout正常工作。

    我找到了一个简单的解决方案,可以用一个类别更新约束(调整大小):


    迟做总比不做好

    对于故事板、IB和Swift:

    只需控制将约束像任何其他控件一样拖动到viewController

    @IBOutlet weak var spaceToTopThatIDecided: NSLayoutConstraint!
    
    然后简单地改变它:

    spaceToTopThatIDecided.constant = 44
    

    就这些

    嘿,罗布-谢谢你的回复;你所说的一切都是恰到好处的(特别是修改
    .constant
    的好处)。然而,事实证明,我的主要错误远不止于此(见我的答案)@sapi嘿,如果这对你有用,那就太好了。我可能误解了这个问题。我上面的回答概述了如何根据popover中视图的完全限定约束来更改popover的框架。我现在从您的解决方案推断,这不是您试图做的,而只是试图解决一个更简单的问题,即确保子视图、
    v1
    v2
    能够调整以适应您的popover框架,对于您的回答,这是一个很好的解决方案。干得好,恭喜你。这实际上是两者的结合。我最初尝试过类似于您的解决方案的方法,但发现popover不会收缩以适应其内容(尽管它会增长)。这是因为我将
    translatesAutoresizingMaskIntoConstraints
    设置为
    NO
    ,就像我通常对autolayout所做的那样