空 UIView 上的自动布局约束无法按预期工作

Posted

技术标签:

【中文标题】空 UIView 上的自动布局约束无法按预期工作【英文标题】:Autolayout Constraints on empty UIView do not work as expected 【发布时间】:2014-02-17 21:07:32 【问题描述】:

所以我设置了一个 UIView,其中包含一个 UIScrollView(和子内容视图),它具有一系列 UILabel 和 UIViews 的子视图,这些子视图根据其中包含的内容而增长和缩小,所有这些都使用 Storyboard 中的 AutoLayout。当我有类似标签 - 标签 - 标签 - 没有任何问题的视图时,这有效,但是如果我在两个标签之间放置一个空 UIView 并在 UIView 上插入子视图,我看不到结果期待。我在情节提要中有以下布局:

...蓝绿色和蓝色视图是增长到无限高度的标签,橙色视图(optionsPanel)是一个空的 UIVIew,我稍后将子视图注入其中。窗口上剩下的东西是 UILabels 和 UISegment 控件。在每一行视图之间,我有一个常量为 8 的垂直空间约束。这一切都很好,直到我不得不放入空的 UIView 并以编程方式注入子视图。我希望工作的代码类似于(optionsPanel 是橙色的 UIView)...

    optionsPanel.translatesAutoresizingMaskIntoConstraints = YES;
    NSArray *options = [product objectForKey:@"options"];
    lastTop = 10;
    for(int i=0;i<options.count; i++) 
        NSDictionary *option = [options objectAtIndex:i];
        NSArray *values = [option objectForKey:@"values"];

        if([self hasNoneValue:values] && values.count == 2) 
            NSDictionary *value = [self notNoneValue:values];

            M13Checkbox *optionCheck = [[M13Checkbox alloc] initWithTitle:[option objectForKey:@"name"]];
            optionCheck.frame = CGRectMake(0, lastTop, 280, 25);
            [optionsPanel addSubview:optionCheck];

            lastTop += 25;
         else 
    

...橙色的 UIView 会神奇地增长,一切都会相应地被推开,但这就是我所看到的:

...橙色的 UIView 根本没有增长,另外两个顶部的 UIView 已经离开屏幕的某个地方。所以我的下一个猜测是使用...关闭 Autoresizing Mask。

optionsPanel.translatesAutoresizingMaskIntoConstraints = NO;

...但是我得到的结果是,一切似乎都在工作,但橙色的 UIView(optionsPanel)无论出于何种原因都没有高度,看起来像:

这越来越接近我的预期,所以我想我会使用类似的代码强制橙色 UIView 的高度...

frame = optionsPanel.frame;
frame.size.height = lastTop;
optionsPanel.frame = frame;

...但这似乎对任何事情都没有影响。

纯粹是猜测,我发现这段代码几乎可以工作,如果我任意将 optionPanel 的原点设置为比所需空间大得多的东西......

    optionsPanel.translatesAutoresizingMaskIntoConstraints = YES;
    NSArray *options = [product objectForKey:@"options"];
    lastTop = 10;
    for(int i=0;i<options.count; i++) 
        NSDictionary *option = [options objectAtIndex:i];
        NSArray *values = [option objectForKey:@"values"];

        if([self hasNoneValue:values] && values.count == 2) 
            NSDictionary *value = [self notNoneValue:values];

            M13Checkbox *optionCheck = [[M13Checkbox alloc] initWithTitle:[option objectForKey:@"name"]];
            optionCheck.frame = CGRectMake(0, lastTop, 280, 25);
            [optionsPanel addSubview:optionCheck];

            lastTop += 25;
         else 
    

    lastTop += 10;

    frame = optionsPanel.frame;
    frame.size.height = lastTop;
    frame.origin.y += 300; //some arbitrarily‎ large number
    optionsPanel.frame = frame;

..这给出了这个结果:

...但显然 AutoLayout 已决定名称标签需要占用额外的空间。这是一种丑陋的方法,但如果我能弄清楚我需要多少空间,那么我可以把所有东西都往下推,如果必须的话。在两个动态大小的标签之间有一个动态 UIView 的秘诀是什么?一切正常???

【问题讨论】:

我发现另一个可行的方法是: NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:priceLabel attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:optionsPanel attribute:NSLayoutAttributeTop multiplier:1 constant:lastTop]; constraint.priority = UILayoutPriorityRequired; [contentView addConstraint:constraint];我将定价标签的顶部设置为选项面板的顶部,其中一个常数是选项面板的高度,它将所有内容都向下推。这并不理想,但很有效。 其实这不太行,optionsPanel 的高度只有~20 像素,所以其他复选框是不可触摸的。 您需要在选项面板和它的子视图之间建立约束关系,以强制选项面板增长以适应内容。你不是免费得到的。当您以编程方式添加子视图时,默认的自动调整大小掩码是UIViewAutoresizingNone,它本质上是说“保持帧不变”,这转化为自动布局约束根本不会影响超级视图的大小。 还要注意第一个屏幕截图中顶层视图右侧的红色图标。该图标告诉您约束存在错误(可能在约束下)。如果您单击该图标,您将获得更详细的说明。 所以基本上你希望所有 3 个框的大小都适合它们的内容,每个框之间有 8 像素的垂直空间? 【参考方案1】:

正如@Timothy 所说,如果您希望橙色视图根据其内容调整大小,则需要手动向其子视图添加约束——默认情况下视图不会这样做。

一般来说,如果您在窗口中使用自动布局,则永远不应该手动设置任何视图的框架。自动布局会覆盖您在每次调用时设置的任何帧,因此即使您设法手动让它工作一秒钟,它也会在下次触发布局时失败。

【讨论】:

SizeToFit 是否不应该让 UIView 自行调整大小? 我实际上不确定 UIView 是否会调整自身大小以适应其子视图(我是 OS X 人),但子视图没有任何约束(而是只有框架) UIView 没有什么可以使用的。框架不计入自动布局,只计入约束。【参考方案2】:

对于在代码中创建的视图,只要它们的translatesAutoresizingMaskIntoConstraints 属性为YES(顺便说一下,默认值),就可以设置它们的框架。

但是,对于在故事板或 nib 中实例化的视图,您不能将其 translatesAutoresizingMaskIntoConstraints 设置为 YES

【讨论】:

以上是关于空 UIView 上的自动布局约束无法按预期工作的主要内容,如果未能解决你的问题,请参考以下文章

UITableViewCell 未按预期显示约束

自动布局无法按预期工作

如何对 UIView 上的自动布局约束引起的大小变化做出反应?

在运行时更改自动布局

程序约束未按预期工作

自动布局中的比例距离约束