以编程方式创建布局约束


84

我知道很多人已经问过很多问题,但是即使有了答案,我也无法解决。

当我处理情节提要上的约束时,这很容易,但是在代码中我很难过。例如,我尝试让视图停留在右侧,并根据屏幕方向显示屏幕高度。这是我的代码:

UIView *myView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 200, 748)];
myView.backgroundColor = [UIColor redColor];
[self.view addSubview:myView];
[self.view addConstraints:[NSLayoutConstraint
    constraintsWithVisualFormat:@"V:|-[myView(>=748)]-|"
    options:0 metrics:nil
    views:NSDictionaryOfVariableBindings(myView)]];

它不满足某些约束。我看不出有什么问题。另外,为什么我不能使用像这样的属性self.myView而不是像这样的局部变量myView


上面的代码中的vivi是什么?
iDev 2012年

14
请将标题更改为“ iOS”,而不是“ IOS”-后者是指思科的交换机/路由器操作系统。使我困惑。谢谢。
阿玛尼2012年

1
关于此的几个问题:(1)当它“不满足某些约束”时,您会遇到什么错误?(2)您是否将自动调整大小转换为对的约束myView?(3)什么vivi(按照ACB的要求)?(4)您是否myView声明了财产self
蒂姆(Tim)

1
蒂姆(Tim),很抱歉,vivi,我拍得太快了……这是myView。翻译是什么意思?我所做的就是上面的代码。关于属性,我还有其他一些声明为属性的视图,但是当我对这些属性实现相同的代码时,它就会崩溃...消息“错误”确实很大,我无法在此处粘贴
Pierre23

从特定视图中删除约束暂时然后为此stackoverflow.com/questions/13388104/...
萨姆乙

Answers:


106

在代码中使用自动版式时,设置框架不会执行任何操作。因此,您在上面的视图中将宽度指定为200的事实对您设置约束没有任何意义。为了使视图的约束集明确无误,它需要四件事:对于任何给定状态,其x位置,y位置,宽度和高度。

当前在上面的代码中,您只有两个(相对于超级视图的高度和相对于超级视图的y位置)。除此之外,您还具有两个必需的约束,这些约束可能会根据视图的超级视图约束的设置方式而发生冲突。如果超级视图具有一个指定的约束,该约束将其高度指定为小于748的某个值,则将出现“无法满足的约束”异常。

在设置约束之前设置视图的宽度这一事实没有任何意义。它甚至都不会考虑旧框架,并将根据为这些视图指定的所有约束条件来计算新框架。在代码中处理自动布局时,我通常只使用initWithFrame:CGRectZero或简单创建一个新视图init

要为您在问题中口头描述的布局创建约束集,您需要添加一些水平约束以约束宽度和x位置,以便提供完整的布局:

[self.view addConstraints:[NSLayoutConstraint
    constraintsWithVisualFormat:@"V:|-[myView(>=748)]-|"
    options:NSLayoutFormatDirectionLeadingToTrailing
    metrics:nil
    views:NSDictionaryOfVariableBindings(myView)]];

[self.view addConstraints:[NSLayoutConstraint
    constraintsWithVisualFormat:@"H:[myView(==200)]-|"
    options:NSLayoutFormatDirectionLeadingToTrailing
    metrics:nil
    views:NSDictionaryOfVariableBindings(myView)]];

从垂直约束开始,对这种布局的口头描述如下:

myView将使用等于标准空间的顶部和底部填充物填充其父视图的高度。myView的超级视图的最低高度为748pts。myView的宽度为200pts,其右视图的右边框等于标准空间。

如果您只是希望视图填充整个超级视图的高度而又不限制超级视图的高度,那么您只需(>=748)在可视格式文本中省略该参数即可。如果您认为(>=748)需要参数来赋予高度-在这种情况下您不需要这样做:使用bar(|)或带空格(|--|)的bar将视图固定到超级视图的边缘,您可以将视图设置为y -位置(将视图固定在单边上)和y高度的位置(将视图固定在两个边上),从而满足您为视图设置的约束。

关于第二个问题:

使用NSDictionaryOfVariableBindings(self.myView)(如果您为myView设置了属性)并将其馈入VFL以self.myView在VFL文本中使用,则当自动布局尝试解析VFL文本时,您可能会遇到异常。它与字典键中的点符号和试图使用的系统有关valueForKeyPath:有关类似的问答,请参见此处


不要忘了像UILabel这样的某些对象具有固有大小,您不必设置该对象的宽度或高度,而只需设置其位置即可。但是,如果您设置高度或宽度,我相信它会同时删除两者,然后您必须同时提供两者。
尼克·特纳2014年

即使此答案不能回答我的问题,也可以帮助我实现一些目标。感谢您的参与!:)
Matej

1
迄今为止,互联网上唯一简洁易读的自动布局介绍。
2015年

请帮助我我的问题是...我不知道如何以编程方式使用约束 stackoverflow.com/questions/36326288/…–

61

嗨,我一直在使用此页面很多限制和“如何”。我花了很长时间才意识到我需要:

myView.translatesAutoresizingMaskIntoConstraints = NO;

使这个例子生效。谢谢Userxxx,Rob M.特别是larsacus的解释和此处的代码,它非常宝贵。

这是完整的代码,可以运行上面的示例:

UIView *myView = [[UIView alloc] init];
myView.backgroundColor = [UIColor redColor];
myView.translatesAutoresizingMaskIntoConstraints = NO;  //This part hung me up 
[self.view addSubview:myView];
//needed to make smaller for iPhone 4 dev here, so >=200 instead of 748
[self.view addConstraints:[NSLayoutConstraint
                           constraintsWithVisualFormat:@"V:|-[myView(>=200)]-|"
                           options:NSLayoutFormatDirectionLeadingToTrailing
                           metrics:nil
                           views:NSDictionaryOfVariableBindings(myView)]];

[self.view addConstraints:[NSLayoutConstraint
                           constraintsWithVisualFormat:@"H:[myView(==200)]-|"
                           options:NSLayoutFormatDirectionLeadingToTrailing
                           metrics:nil
                           views:NSDictionaryOfVariableBindings(myView)]];

11

迅捷版

为Swift 3更新

此示例将显示两种方法,以编程方式添加以下约束,就像在Interface Builder中进行添加一样:

宽度和高度

在此处输入图片说明

集装箱中心

在此处输入图片说明

样板代码

override func viewDidLoad() {
    super.viewDidLoad()

    // set up the view
    let myView = UIView()
    myView.backgroundColor = UIColor.blue
    myView.translatesAutoresizingMaskIntoConstraints = false
    view.addSubview(myView)

    // Add constraints code here (choose one of the methods below)
    // ...
}

方法1:锚样式

// width and height
myView.widthAnchor.constraint(equalToConstant: 200).isActive = true
myView.heightAnchor.constraint(equalToConstant: 100).isActive = true

// center in container
myView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
myView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true

方法2:NSLayoutConstraint样式

// width and height
NSLayoutConstraint(item: myView, attribute: NSLayoutAttribute.width, relatedBy: NSLayoutRelation.equal, toItem: nil, attribute: NSLayoutAttribute.notAnAttribute, multiplier: 1, constant: 200).isActive = true
NSLayoutConstraint(item: myView, attribute: NSLayoutAttribute.height, relatedBy: NSLayoutRelation.equal, toItem: nil, attribute: NSLayoutAttribute.notAnAttribute, multiplier: 1, constant: 100).isActive = true

// center in container
NSLayoutConstraint(item: myView, attribute: NSLayoutAttribute.centerX, relatedBy: NSLayoutRelation.equal, toItem: view, attribute: NSLayoutAttribute.centerX, multiplier: 1, constant: 0).isActive = true
NSLayoutConstraint(item: myView, attribute: NSLayoutAttribute.centerY, relatedBy: NSLayoutRelation.equal, toItem: view, attribute: NSLayoutAttribute.centerY, multiplier: 1, constant: 0).isActive = true

笔记

  • 相对于NSLayoutConstraint样式,锚定样式是首选的方法,但是只有iOS 9才提供锚样式,因此,如果支持iOS 8,则仍应使用NSLayoutConstraint样式。
  • 另请参阅以编程方式创建约束文档。
  • 有关添加固定约束的类似示例,请参见此答案

5

关于第二个关于属性的问题,self.myView仅当您在类中将其声明为属性时,才可以使用。由于myView是局部变量,因此不能那样使用。有关此的更多详细信息,我建议您仔细阅读Declared Properties上的Apple文档,


5

为什么不能使用self.myView像myView这样的属性而不是像myView这样的局部变量?

尝试使用:

NSDictionaryOfVariableBindings(_view)

代替 self.view


这使我的应用程序崩溃了,并显示以下消息:“无法解析约束格式:polylineImageView不是视图字典中的键。”
大勒

4

另请注意,在iOS9中,我们可以使用新的帮助器类NSLayoutAnchor的子类编程方式定义约束“更简洁,更易于阅读”

doc中的示例:

[self.cancelButton.leadingAnchor constraintEqualToAnchor:self.saveButton.trailingAnchor constant: 8.0].active = true;
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.