以编程方式为 UIView 子视图设置自动布局约束

Programatically setting auto layout constraints for a UIView's subviews

下面我提供了一些代码供您查看。我正在尝试采用自定义 UIView 并向其添加另一个自定义子视图。这个子视图应该被限制在 parent 视图中,这样它基本上只是以相同的尺寸放在顶部,而 parent 只是作为一个包装器。

我尝试过使用NSLayoutConstraint,但到目前为止失败得很惨。该视图从未真正显示出来。我有一个左、右、下和上约束,它们应该与 parent 视图对齐。

我的第一个问题是有人在使用以下方法时请解释或纠正我的逻辑。我认为的项目参数是您要为其设置约束的实际视图 (customViewChild)。该属性是说我希望 customViewChild 的左边缘用于此约束。 relatedBy 看起来很简单,尽管我可能是错的,最后 toItem 指向 self,这是我的 CustomViewParent,它也有一个 .left 属性来表示我希望我的 child 和 parent 的左边缘对齐。这个逻辑有问题还是我做错了什么?

NSLayoutConstraint(item: customViewChild!, 
            attribute: .left, 
            relatedBy: .equal,
            toItem: self,
            attribute: .left, 
            multiplier: 1.0, 
            constant: 0.0)

我知道下面的例子可以很容易地用 IB 完成,但我试图理解 NSLayoutConstraint,所以请提供有关的答案。最后,如果有人真的可以更正这段代码,那么我就有了一个工作示例,那就太棒了。

class CustomViewParent: UIView {

    var customViewChild: UIView?

    override init(frame: CGRect) {
        super.init(frame: frame)

        setConstraints()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)

        setConstraints()
    }

    func setConstraints() {
        customViewChild = UIView()

        addSubview(customViewChild!)
        customViewChild?.translatesAutoresizingMaskIntoConstraints = false

        let leftConstraint = NSLayoutConstraint(item: customViewChild!, 
            attribute: .left, 
            relatedBy: .equal,
            toItem: self,
            attribute: .left, 
            multiplier: 1.0, 
            constant: 0.0).isActive = true

        let rightConstraint = NSLayoutConstraint(item: customViewChild!, 
            attribute: .right, 
            relatedBy: .equal,
            toItem: self,
            attribute: .right, 
            multiplier: 1.0, 
            constant: 0.0).isActive = true

        let topConstraint = NSLayoutConstraint(item: customViewChild!, 
            attribute: .top, 
            relatedBy: .equal,
            toItem: self,
            attribute: .top,
            multiplier: 1.0, 
            constant: 0.0).isActive = true

        let bottomConstraint = NSLayoutConstraint(item: customViewChild!, 
            attribute: .bottom, 
            relatedBy: .equal,
            toItem: self,
            attribute: .bottom, 
            multiplier: 1.0, 
            constant: 0.0).isActive = true

        customViewChild.addConstraint([leftConstraint, rightConstraint, topConstraint, bottomConstraint]);
    }

}

三件事:

  1. 您不需要使用 addConstraint。只需将约束的 isActive 设置为 true
  2. 同时将 isActive 设置为 true 并将其结果分配给常量是没有意义的。设置 isActive 属性 不会 return NSLayoutConstraint。它 returns ().
  3. 您应该使用 .leading.trailing 而不是 .left.right

进行这些更改后,以下内容应该会起作用:

func setConstraints() {
    customViewChild = UIView()

    addSubview(customViewChild!)
    customViewChild?.translatesAutoresizingMaskIntoConstraints = false

    NSLayoutConstraint(item: customViewChild!, 
        attribute: .leading, 
        relatedBy: .equal,
        toItem: self,
        attribute: .leading, 
        multiplier: 1.0, 
        constant: 0.0).isActive = true

    NSLayoutConstraint(item: customViewChild!, 
        attribute: .trailing, 
        relatedBy: .equal,
        toItem: self,
        attribute: .trailing, 
        multiplier: 1.0, 
        constant: 0.0).isActive = true

    NSLayoutConstraint(item: customViewChild!, 
        attribute: .top, 
        relatedBy: .equal,
        toItem: self,
        attribute: .top,
        multiplier: 1.0, 
        constant: 0.0).isActive = true

    NSLayoutConstraint(item: customViewChild!, 
        attribute: .bottom, 
        relatedBy: .equal,
        toItem: self,
        attribute: .bottom, 
        multiplier: 1.0, 
        constant: 0.0).isActive = true
}

您可能会发现这更容易一些,也更易读...

func setConstraints() {

    if customViewChild == nil {
        customViewChild = UIView()

        addSubview(customViewChild!)
        customViewChild?.translatesAutoresizingMaskIntoConstraints = false

        customViewChild?.leftAnchor.constraint(equalTo: self.leftAnchor).isActive = true
        customViewChild?.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
        customViewChild?.rightAnchor.constraint(equalTo: self.rightAnchor).isActive = true
        customViewChild?.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
    }

}