以编程方式添加CenterX/CenterY约束

Mar*_*man 73 xcode ios autolayout nslayoutconstraint swift

我有一个UITableViewController,如果没有任何显示,它不会显示任何部分.我添加了一个标签,向用户表明此代码无法显示:

label = UILabel(frame: CGRectMake(20, 20, 250, 100))
label.text = "Nothing to show"
self.tableView.addSubview(label)
Run Code Online (Sandbox Code Playgroud)

但现在,我希望它在水平和垂直方向上居中.通常,我会在屏幕截图中选择突出显示的两个选项(加上高度和宽度的选项):

在此输入图像描述

我尝试了以下代码来添加约束但应用程序崩溃时出现错误:

label = UILabel(frame: CGRectMake(20, 20, 250, 100))
label.text = "Nothing to show"

let xConstraint = NSLayoutConstraint(item: label, attribute: .CenterX, relatedBy: .Equal, toItem: self.tableView, attribute: .CenterX, multiplier: 1, constant: 0)
let yConstraint = NSLayoutConstraint(item: label, attribute: .CenterY, relatedBy: .Equal, toItem: self.tableView, attribute: .CenterY, multiplier: 1, constant: 0)

label.addConstraint(xConstraint)
label.addConstraint(yConstraint)
Run Code Online (Sandbox Code Playgroud)

错误:

When added to a view, the constraint's items must be descendants of that view (or the view itself). This will crash if the constraint needs to be resolved before the view hierarchy is assembled. Break on -[UIView _viewHierarchyUnpreparedForConstraint:] to debug.
2014-12-23 08:17:36.755 [982:227877] *** Assertion failure in -[UILabel _layoutEngine_didAddLayoutConstraint:roundingAdjustment:mutuallyExclusiveConstraints:], /SourceCache/UIKit/UIKit-3318.16.21/NSLayoutConstraint_UIKitAdditions.m:560
Run Code Online (Sandbox Code Playgroud)

标签应始终水平和垂直居中,因为应用程序支持设备的旋转.

我究竟做错了什么?如何成功添加这些约束?

谢谢!

vac*_*ama 138

Swift 3/Swift 4的更新:

从iOS 8开始,您可以并且应该通过将其isActive属性设置为来激活约束true.这使约束能够将自己添加到正确的视图中.您可以通过传递包含约束的数组来一次激活多个约束NSLayoutConstraint.activate()

let label = UILabel(frame: CGRect.zero)
label.text = "Nothing to show"
label.textAlignment = .center
label.backgroundColor = .red  // Set background color to see if label is centered
label.translatesAutoresizingMaskIntoConstraints = false
self.tableView.addSubview(label)

let widthConstraint = NSLayoutConstraint(item: label, attribute: .width, relatedBy: .equal,
                                         toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: 250)

let heightConstraint = NSLayoutConstraint(item: label, attribute: .height, relatedBy: .equal,
                                          toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: 100)

let xConstraint = NSLayoutConstraint(item: label, attribute: .centerX, relatedBy: .equal, toItem: self.tableView, attribute: .centerX, multiplier: 1, constant: 0)

let yConstraint = NSLayoutConstraint(item: label, attribute: .centerY, relatedBy: .equal, toItem: self.tableView, attribute: .centerY, multiplier: 1, constant: 0)

NSLayoutConstraint.activate([widthConstraint, heightConstraint, xConstraint, yConstraint])
Run Code Online (Sandbox Code Playgroud)

改善方案:

由于最初回答了这个问题,因此引入了布局锚点,使得创建约束变得更加容易.在这个例子中,我创建约束并立即激活它们:

label.widthAnchor.constraint(equalToConstant: 250).isActive = true
label.heightAnchor.constraint(equalToConstant: 100).isActive = true
label.centerXAnchor.constraint(equalTo: self.tableView.centerXAnchor).isActive = true
label.centerYAnchor.constraint(equalTo: self.tableView.centerYAnchor).isActive = true
Run Code Online (Sandbox Code Playgroud)

注意:创建和激活约束之前,始终将子视图添加到视图层次结构中.


原答案:

约束参考NSLayoutConstraint.activate().由于您self.tableView要将标签添加为子视图,因此需要将约束添加到"共同祖先":

NSLayoutConstraint.activate([
    label.widthAnchor.constraint(equalToConstant: 250),
    label.heightAnchor.constraint(equalToConstant: 100),
    label.centerXAnchor.constraint(equalTo: self.tableView.centerXAnchor),
    label.centerYAnchor.constraint(equalTo: self.tableView.centerYAnchor)
])
Run Code Online (Sandbox Code Playgroud)

正如@mustafa和@kcstricks在评论中指出的那样,你需要设置 self.tableViewlabel.translatesAutoresizingMaskIntoConstraints.当你这样做,你还需要指定false,并width因为框架不再使用有约束的标签.最后,您还应将其设置为heighttextAlignment使文本在标签中居中.

   self.tableView.addConstraint(xConstraint)
   self.tableView.addConstraint(yConstraint)
Run Code Online (Sandbox Code Playgroud)


Sur*_*gch 32

容器中心

在此输入图像描述

下面的代码与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 code for one of the constraint methods below
    // ...
}
Run Code Online (Sandbox Code Playgroud)

方法1:锚式

myView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
myView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
Run Code Online (Sandbox Code Playgroud)

方法2:NSLayoutConstraint样式

NSLayoutConstraint(item: myView, attribute: NSLayoutConstraint.Attribute.centerX, relatedBy: NSLayoutConstraint.Relation.equal, toItem: view, attribute: NSLayoutConstraint.Attribute.centerX, multiplier: 1, constant: 0).isActive = true
NSLayoutConstraint(item: myView, attribute: NSLayoutConstraint.Attribute.centerY, relatedBy: NSLayoutConstraint.Relation.equal, toItem: view, attribute: NSLayoutConstraint.Attribute.centerY, multiplier: 1, constant: 0).isActive = true
Run Code Online (Sandbox Code Playgroud)

笔记

  • Anchor样式是NSLayoutConstraintStyle 的首选方法,但它仅适用于iOS 9,所以如果你支持iOS 8,那么你仍然应该使用NSLayoutConstraintStyle.
  • 您还需要添加长度和宽度约束.
  • 我的完整答案就在这里.


小智 10

ObjectiveC等价物是:

    myView.translatesAutoresizingMaskIntoConstraints = NO;

    [[myView.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor] setActive:YES];

    [[myView.centerYAnchor constraintEqualToAnchor:self.view.centerYAnchor] setActive:YES];
Run Code Online (Sandbox Code Playgroud)


YaB*_*eep 8

以编程方式,您可以通过添加以下约束来完成此操作.

NSLayoutConstraint *constraintHorizontal = [NSLayoutConstraint constraintWithItem:self  
                                                                      attribute:NSLayoutAttributeCenterX 
                                                                      relatedBy:NSLayoutRelationEqual 
                                                                         toItem:self.superview 
                                                                      attribute:attribute 
                                                                     multiplier:1.0f 
                                                                       constant:0.0f];

NSLayoutConstraint *constraintVertical = [NSLayoutConstraint constraintWithItem:self
                                                                        attribute:NSLayoutAttributeCenterY 
                                                                        relatedBy:NSLayoutRelationEqual
                                                                           toItem:self.superview 
                                                                        attribute:attribute 
                                                                       multiplier:1.0f
                                                                         constant:0.0f];
Run Code Online (Sandbox Code Playgroud)


PiK*_*Key 7

在 Swift 5 中,它看起来像这样:

label.translatesAutoresizingMaskIntoConstraints = false
label.centerXAnchor.constraint(equalTo: vc.view.centerXAnchor).isActive = true
label.centerYAnchor.constraint(equalTo: vc.view.centerYAnchor).isActive = true
Run Code Online (Sandbox Code Playgroud)