自动布局 - 使视图高度相对于父视图高度的一半

141

最近我开始研究自动布局,但卡在一个看起来非常微不足道的问题上。我有一个视图想要置于屏幕顶部,占据屏幕高度的一半。如果不用自动布局会很简单——把它固定在那里,并告诉它在父视图大小变化时垂直扩展即可。

现在,我无论如何都看不到该怎么做。这是我尝试设置后得到的结果:

autolayout blues

底部空间约束设置为“等于284”,这是绝对值,并且在我切换到iPhone4布局时完全没用,因为它会始终在屏幕底部保留284个点的空间,使得视图不再占屏幕的一半大小。而且没有办法将该约束设置为其他任何视图高度的一部分。

苦苦挣扎了一段时间后,我唯一能想到的方法就是在该视图下方引入另一个视图,平均固定它们的高度,让它们相互居于上下位置,然后将第二个(底部)视图设置为不可见...,但这似乎有些丑陋!

我是不是漏掉了什么明显的东西?..


1
我认为这不是丑陋的,而是使用IB获得所需内容的聪明技巧。我已经做过这个,当你使用适当的元素名称时,你可以清楚地知道发生了什么。你甚至可以在不同位置或中心有第三个元素,并根据这两个子视图改变大小。 - Jelle
6个回答

193

可以设置任何视图之间精确比例的Storyboard解决方案:

设置等高约束

现在:

编辑约束的乘数

受益!

结果

P.S. 请注意,此方法适用于不同嵌套级别上的视图,并且(显然)适用于宽度。

P.P.S. 有时候翻转约束的第一和第二个项目或设置反向乘数(例如2而不是0.5)可能会有所帮助(但是如果您不了解视图之间的关系,则这些方法将无济于事)。


1
第二步似乎对我不起作用。除了切换“约束到边缘”之外,我无法在面板中选择任何内容。我正在尝试将UITableViewCell中UIImageView的宽度设置为内容视图的50%。 - DrMickeyLauer
2
更新:显然,界面构建器不允许内容视图成为任何自动布局约束的显式目标。我必须插入一个虚拟子视图作为内容视图的子视图才能使其正常工作。 - DrMickeyLauer
1
这对我有效。你需要在列表中选择两个视图而不是构建器屏幕。对于百分比,请将较小的视图除以较大的视图以获得乘数值,例如较小的视图25,较大的视图135-25/135=0.185。将此设置为乘数值,以获得x1和x2均为25但随着较大的6和6 plus等而扩大的视图。 - latenitecoder
1
这对我有用,但请注意,我还必须添加三个约束条件,将子视图的边距约束设置为0。谢谢。 - raddevus
@Houman,没错,你可以在这里了解更多关于约束数学的知识:https://developer.apple.com/library/archive/documentation/UserExperience/Conceptual/AutolayoutPG/ProgrammaticallyCreatingConstraints.html。在这种情况下,非零常数会引入不必要的偏差,因此我们只关心乘数。你可以在界面构建器中自己尝试一下! - Fyodor Volchyok
显示剩余2条评论

175

现在,至少从Xcode 5.1.1开始,在IB中可以实现这个功能。虽然我花了一些时间才弄清楚,但它实际上非常简单:

首先创建一个基本的顶部对齐约束(您还需要设置底部、左侧和右侧约束,就像平常一样)。 然后选择约束并导航到属性检查器:

上述步骤演示

接着,您可以调整乘数。如果您想要它是超级视图的50%,则将其保留为1,因为它是根据超级视图的中心对齐的。这也是创建其他百分比视图的好方法,例如超级视图的25%。

上述第二步演示


不错 :) 我认为这篇文章应该被标记为已接受的答案 :) iOS开发者通常更喜欢使用Interface Builder解决方案,而不是类似于代码的解决方案。 - hqt
@hqt,谢谢。我认为当被接受的答案被写出来时,这种方法还不可用。有时候提问者不会回顾旧问题或关心更改被接受的答案。但最终我只是在这里帮忙,很高兴它起到了作用! - Firo
3
有点困惑,我试过这个方法,它只是将视图居中于父视图,而没有调整视图的高度。 - netwire
@Dean,你需要确保“第一项”是“View.Top”,而不是“View.Center Y”。否则,它只会居中。你还需要确保其他约束条件设置正确,以处理视图的其他边缘。 - Firo
1
View.Top等于Superview.Center Y乘以1不会给你任何高度。这个答案是不完整的。你只需要考虑一下你所说的话,就可以看到它给你一个横穿中心的线!我会编辑这个答案,以明确你所谈论的其他约束条件。 - SmileBot
如果您的其他约束条件设置正确,它就会生效。如果您的底部被固定在正确的位置(底部),那么它将恰好占据父视图的一半。我会编辑答案并添加这些信息。谢谢。 - Firo

31

稍微再多花一点时间,我想出了以下解决方案。

我将其标记为答案,但并不是很令人满意,因为它假设您实际上无法在Interface Builder中完成此操作,但正确的约束条件可以在代码中后续添加:

- (void) viewWillAppear:(BOOL)animated
{

    NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:upperview
                                                                 attribute:NSLayoutAttributeHeight 
                                                                 relatedBy:0 
                                                                    toItem:self.view
                                                                 attribute:NSLayoutAttributeHeight
                                                                multiplier:.5 
                                                                  constant:0];
    [self.view addConstraint:constraint];

}

基本上,它会针对self.view的高度设置一个0.5的乘数,作用于upperview。 我不得不将IB中底部垂直空间约束的优先级设置为低于1000,以避免大量的运行时约束错误消息。

如果有人能展示如何在Interface Builder中实现这一点,那就更好了回答我的问题,否则我想现在这是最好的情况了???


3
我认为现在这已经是最好的了。如果苹果公司能够让我们在接口生成器中访问乘数值,那就太好了,这样就可以设置常量以及乘数值了。 - rdelmar
3
对于任何查看此答案的人,Xcode 5.1 现在可以通过 Interface Builder 设置乘数。现在,我可以通过 IB 配置视图,使它们的高度为其父视图的一半。 - Mark Krenek

11
比Fyodor Volchyok的答案稍微容易和直接一些。 - 按住控制键并单击子视图。 - 仍然按住命令键,将光标拖到父视图,然后单击父视图。 - 选择“纵横比”。

enter image description here

请按以下步骤操作: - 点击“尺寸检查器”。 - 双击约束条件。 enter image description here - 确保两个项目都选择了“高度”。 enter image description here - 然后将“乘数”更改为屏幕的一半(或任何您希望超级视图的分数)。 enter image description here

简单快捷的方法!谢谢伙计 - Abdullah Saeed

7

如果您有两个视图需要具有相同的高度,代码中还有另一种可能性:只需将view2的高度设置为view1的高度(这里的技巧是不显式设置view1的高度)。

    [self.view addConstraints:[NSLayoutConstraint
        constraintsWithVisualFormat:@"V:[topLayoutGuide]-0-[_view1]-0-[_view2(==_view1)]-0-[bottomLayoutGuide]"
                            options:0
                            metrics:nil
                              views:viewsDict]];

没想到你可以像那样引用其他视图的宽度/高度。如果你已经在可视化格式语言中,这是我认为最清晰的答案。 - loeschg
@brainray 的示例也在 developer.apple.com 上有详细解释。 - alecs.popa

0

以下是 Mete 回答的 Swift 版本:

    override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.



    upperView.translatesAutoresizingMaskIntoConstraints = false


    var constraint = NSLayoutConstraint(item: upperView,
                                        attribute: NSLayoutAttribute.top,
                                        relatedBy: NSLayoutRelation.equal,
                                        toItem: self.view,
                                        attribute: NSLayoutAttribute.top,
                                        multiplier: 1,
                                        constant: 0)

    self.view.addConstraint(constraint)


    constraint = NSLayoutConstraint(item: upperView,
                                    attribute: NSLayoutAttribute.height,
                                    relatedBy: NSLayoutRelation.equal,
                                    toItem: self.view,
                                    attribute: NSLayoutAttribute.height,
                                    multiplier: 0.5,
                                    constant: 0)

    self.view.addConstraint(constraint)


    constraint = NSLayoutConstraint(item: upperView,
                                    attribute: NSLayoutAttribute.leading,
                                    relatedBy: NSLayoutRelation.equal,
                                    toItem: self.view,
                                    attribute: NSLayoutAttribute.leading,
                                    multiplier: 1,
                                    constant: 0)

    self.view.addConstraint(constraint)


    constraint = NSLayoutConstraint(item: upperView,
                                    attribute: NSLayoutAttribute.trailing,
                                    relatedBy: NSLayoutRelation.equal,
                                    toItem: self.view,
                                    attribute: NSLayoutAttribute.trailing,
                                    multiplier: 1,
                                    constant: 0)

    self.view.addConstraint(constraint)


}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接