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

Posted

技术标签:

【中文标题】使用 NSLayoutConstraints 调整当前视图的大小【英文标题】:Resize current view using NSLayoutConstraints 【发布时间】:2013-06-16 04:14:20 【问题描述】:

我正在尝试使用NSLayoutConstraints 设置视图的布局。

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

所以基本上,我有:

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 比对 OS X 更熟悉),但这是 NSPopover 的内容视图。

我需要添加什么约束来实现这一点?

【问题讨论】:

【参考方案1】:

有几个问题:

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

    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 约束相结合,现在使视图的布局明确。

    完成后,您还需要告诉视图控制器在应用自动布局时通知弹出框控制器其内容大小。因此,您的视图控制器可以实现 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;
    
    

    注意,frame 的设置非常奇怪,但是如果您不将原点重置为0.0, 0.0,您的控件将不会出现在正确的位置。您必须这样做似乎不对,但根据我的经验,您必须这样做。

    与您的问题有些无关,您提到您正在删除v1Height“通过删除它,重新创建它,然后阅读它”。这是不必要的,也不推荐。 constant 属性是可修改的。作为docs say

    “与其他属性不同,constant 可以在创建约束后修改。在现有约束上设置 constant 比删除约束并添加一个与旧约束一样但具有新的constant。”

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

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

【讨论】:

嘿 Rob - 感谢您的回复;您所说的一切都是正确的(尤其是修改.constant 的优势)。然而,事实证明,我的主要错误远不止于此(见我的回答) @sapi 嘿,如果这对你有用,那就太好了。我可能误解了这个问题。我上面的回答概述了如何根据弹出框内视图的完全限定约束来更改弹出框的框架。我现在从您的解决方案中推断这不是您想要做的,而只是试图解决一个更简单的问题,即尝试确保子视图 v1v2 进行调整以适应框架你的弹出框,你的回答是一个很好的解决方案。干得好,恭喜。 它实际上是两者的结合。我最初尝试了与您的解决方案类似的方法,但发现弹出框不会缩小以适应其内容(尽管它会增长)。原来是因为我将translatesAutoresizingMaskIntoConstraints 设置为NO,就像我通常对自动布局所做的那样【参考方案2】:

事实证明,NSPopoverController 是规则的一个例外,translatesAutoresizingMaskIntoConstraints 必须是 YES 才能使自动布局正常工作。

【讨论】:

【参考方案3】:

迟到总比没有好...

对于 Storyboard、IB 和 Swift:

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

@IBOutlet weak var spaceToTopThatIDecided: NSLayoutConstraint!

然后简单地改变它:

spaceToTopThatIDecided.constant = 44

就是这样!

【讨论】:

【参考方案4】:

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

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

【讨论】:

以上是关于使用 NSLayoutConstraints 调整当前视图的大小的主要内容,如果未能解决你的问题,请参考以下文章

在 UITableView 的标题视图上使用 NSLayoutConstraints

带有 NSLayoutConstraints 的 UIView 灵活高度

使用 NSLayoutConstraints 时的警告

使用 NSLayoutConstraints 在 UITextView 中将 UILabel 居中

使用 NSLayoutConstraints 在 UIView 上简单滑动动画

在代码中创建 NSLayoutConstraints