使用 TopLayoutGuide 的制图约束

Cartography constraints with TopLayoutGuide

我有一个视图,我希望它看起来像这样:

|---------------|
|               | <- navBar
|---------------|
|               | <- topView
|---------------|
|               |
|               |
|               |
|---------------|

我想要的一切就是坚持 topView.top 到 navBar.bottom。我决定使用制图并实现以下代码(尝试坚持使用 MVC ofc):

在我的 UIViewController 子类中:

override func viewWillLayoutSubviews() {
    super.viewWillLayoutSubviews()

    aView?.topLayoutGuide = self.topLayoutGuide // where aView is my subclass of UIView, inserted in loadView method
}

在我的 UIView 子类中:

var topLayoutGuide: UILayoutSupport?

override func updateConstraints() {
    var constraint = NSLayoutConstraint?()
    layout(topView) { (topView) in
        constraint = topView.top == topView.superview!.top
    }
    topView.superview!.removeConstraint(constraint!)

    layout(topView) { topView in
        topView.top == topView.superview!.top + (self.topLayoutGuide?.length ?? 0)
        topView.height == 67
        topView.left == topView.superview!.left
        topView.width == topView.superview!.width
    }

    super.updateConstraints()
}

问题是我收到以下日志,但我不知道如何解决:

Unable to simultaneously satisfy constraints.
[...]
(
    "<NSLayoutConstraint:0x7fe6a64e4800 V:|-(64)-[UIView:0x7fe6a6505d80]   (Names: '|':MyApp.MyView:0x7fe6a360d4c0 )>",
    "<NSLayoutConstraint:0x7fe6a3538a80 V:|-(0)-[UIView:0x7fe6a6505d80]   (Names: '|':MyApp.MyView:0x7fe6a360d4c0 )>"
)

看来我需要一些帮助。如何正确地做到这一点?我不想在 UIViewController 中实施约束,也不想使用 Storyboards.

感谢您的帮助!

一个解决方案:创建对该特定 NSLayoutConstraint 的引用,并更新其 constant:

var topLayoutConstraint: NSLayoutConstraint!

override func updateConstraints() { 
    layout(topView) { topView in
        topLayoutConstraint = topView.top == topView.superview!.top
        topView.height == 67
        topView.left == topView.superview!.left
        topView.width == topView.superview!.width
    }

    super.updateConstraints()
}

...然后,您可以像这样调整 NSLayoutConstraint 的常量:

topLayoutConstraint.constant = 50

剩下的唯一问题是 - 你什么时候更新 topLayoutConstraint?一种解决方案是创建一个协议,MyViewInterface:

protocol MyViewInterface: class {
    var topLayoutGuideLength: CGFloat { get set }
}

然后,在我们的UIView中,当那个topLayoutGuideLength属性改变的时候,我们调整NSLayoutConstraintconstant

public class MyView: UIView, MyViewInterface {
    public var topLayoutGuideLength: CGFloat = 0 {
        didSet {
            topLayoutConstraint.constant = topLayoutGuideLength
        }
    }
}

最后,在我们的 UIViewController(我们的 topLayoutGuide 居住的地方):

public class myViewController: UIViewController {

    private var myView: MyView

    // ...

    public override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()

        myView.topLayoutGuideLength = topLayoutGuide.length
    }
}

最后的结果?每当 UIViewController 触发 viewDidLayoutSubviews() 时,我们的 myViewtopLayoutGuideLength 属性 就会更新,这会触发 topLayoutConstraint 的更改constant.

又一次缺少制图文档...

我在制图学中发现 topLayoutGuideCartographybottomLayoutGuideCartography 属性作为 UIViewController 扩展。使用它们可以在不覆盖 viewDidLayoutSubviews

的情况下为您提供所需的输出

您可以简单地使用此 属性 来锚定视图的顶部。

override func updateConstraints() { 
    layout(topView) { topView in
       topView.top == topLayoutGuideCartography
       topView.height == 67
       topView.left == topView.superview!.left
       topView.width == topView.superview!.width
    }

    super.updateConstraints()
}