以编程方式添加前导/顶部约束

adding leading / top constraints programmatically

我有以下代码用于高度和宽度约束。尝试添加前导约束和顶部约束时崩溃。我还有其他组按钮,它们具有高度、宽度、前导、顶部约束,但它们都设置在故事板上,所以我认为这些是我必须添加到每个按钮的仅有的 4 个约束。

我有 7 个按钮,每个对应一周中的一天。当我添加代码来执行前导和顶部约束时,它会因以下错误代码而中断。它仅适用于 height/width。我猜这与我添加子视图的方式或按钮与视图控制器的关系有关,或者在以编程方式进行时我需要的不仅仅是我一直在使用的 4 个约束(前导、顶部、宽度、高度)在故事板上。

func setupWeekdayButtons() {
    self.weeklyButtons = [self.mondayButton, self.tuesdayButton, self.wednesdayButton, self.thursdayButton, self.fridayButton, self.saturdayButton, self.sundayButton]


    for i in 0...6 {
        print(i)

        self.weeklyButtons[i].translatesAutoresizingMaskIntoConstraints = false
        self.weeklyButtons[i].setTitle(self.weekdayLabels[i], for: .normal)
        self.weeklyButtons[i].layer.borderColor = UIColor.black.cgColor
        self.weeklyButtons[i].titleLabel?.textAlignment = .center
        self.weeklyButtons[i].layer.borderWidth = 1.0
        self.weeklyButtons[i].layer.cornerRadius = 6.0
        self.weeklyButtons[i].setTitleColor(.black, for: .normal)
        self.weeklyButtons[i].setTitleColor(.red, for: .selected)
        self.weeklyButtons[i].addTarget(self, action: #selector(selectedDailyButton), for: .touchUpInside)
        self.view.addSubview(self.weeklyButtons[i])

        let heightConstraint = NSLayoutConstraint(
            item: self.weeklyButtons[i],
            attribute: NSLayoutConstraint.Attribute.height,
            relatedBy: NSLayoutConstraint.Relation.equal,
            toItem: nil,
            attribute: NSLayoutConstraint.Attribute.notAnAttribute,
            multiplier: 1.0,
            constant: 30
        )
        let widthConstraint = NSLayoutConstraint(
            item: self.weeklyButtons[i],
            attribute: NSLayoutConstraint.Attribute.width,
            relatedBy: NSLayoutConstraint.Relation.equal,
            toItem: nil,
            attribute: NSLayoutConstraint.Attribute.notAnAttribute,
            multiplier: 1.0,
            constant: 30
        )
        let leadingConstraint = NSLayoutConstraint(
            item: self.weeklyButtons[i],
            attribute: NSLayoutConstraint.Attribute.leading,
            relatedBy: NSLayoutConstraint.Relation.equal,
            toItem: self.view,
            attribute: NSLayoutConstraint.Attribute.leading,
            multiplier: 1.0,
            constant: 100
        )

        let topConstraint = NSLayoutConstraint(
            item: self.weeklyButtons[i],
            attribute: NSLayoutConstraint.Attribute.top,
            relatedBy: NSLayoutConstraint.Relation.equal,
            toItem: self.view,
            attribute: NSLayoutConstraint.Attribute.top,
            multiplier: 1.0,
            constant: 100
        )
        self.weeklyButtons[i].addConstraint(heightConstraint)
        self.weeklyButtons[i].addConstraint(widthConstraint)
        self.weeklyButtons[i].addConstraint(leadingConstraint)
        self.weeklyButtons[i].addConstraint(topConstraint)
    }
}

2019-03-07 14:38:59.176638-0500 Daily[27852:1408014] [LayoutConstraints] The view hierarchy is not prepared for the constraint: 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(UIConstraintBasedLayout) _viewHierarchyUnpreparedForConstraint:] to debug.

2019-03-07 14:38:59.177816-0500 Daily[27852:1408014] [LayoutConstraints] View hierarchy unprepared for constraint. Constraint: Container hierarchy: > | > View not found in container hierarchy: > That view's superview: NO SUPERVIEW

2019-03-07 14:38:59.192176-0500 Daily[27852:1408014] *** Terminating app due to uncaught exception 'NSGenericException', reason: 'Unable to install constraint on view. Does the constraint reference something from outside the subtree of the view? That's illegal. constraint: view:>'

我已经有一段时间没有在代码中添加约束了,但是如果没记错的话,您必须在添加约束之前将视图添加到视图层次结构中。 (这就是错误消息所暗示的。)

        self.weeklyButtons[i].addConstraint(leadingConstraint)

约束涉及weeklyButtons[i]self.view。如果使用 addConstraint 激活约束,则必须将约束添加到两个视图的共同祖先。这就是此错误消息告诉您的内容:

When added to a view, the constraint's items must be descendants of that view (or the view itself).

因为 self.viewweeklyButtons[i] 的父视图,它算作两个视图的共同祖先。所以在这种情况下,您可以将约束添加到 self.view:

self.view.addConstraint(leadingConstraint)

但不要那样做。从iOS8开始,你可以直接激活一个约束,UIKit会自动将它添加到正确的视图中:

leadingConstraint.isActive = true

但不要那样做。由于您要连续添加四个约束,因此像这样同时激活四个约束可能会更有效一些:

NSLayoutConstraint.activate([
    leadingConstraint,
    topConstraint,
    widthConstraint,
    heightConstraint])

但不要那样做。 自 iOS 9 以来,出现了一种更具可读性的创建约束的方法:

NSLayoutConstraint.activate([
    self.weeklyButtons[i].heightAnchor.constraint(equalToConstant: 30),
    self.weeklyButtons[i].widthAnchor.constraint(equalToConstant: 30),
    self.weeklyButtons[i].leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 100),
    self.weeklyButtons[i].topAnchor.constraint(equalTo: view.topAnchor, constant: 100),
    ])

但不要那样做。 使用 for/in 循环而不是索引变量 i:

func setupWeekdayButtons() {
    weeklyButtons = [mondayButton, tuesdayButton, wednesdayButton, thursdayButton, fridayButton, saturdayButton, sundayButton]

    for (button, title) in zip(weeklyButtons, weekdayLabels) {
        button.translatesAutoresizingMaskIntoConstraints = false
        button.setTitle(title, for: .normal)
        button.layer.borderColor = UIColor.black.cgColor
        button.titleLabel?.textAlignment = .center
        button.layer.borderWidth = 1.0
        button.layer.cornerRadius = 6.0
        button.setTitleColor(.black, for: .normal)
        button.setTitleColor(.red, for: .selected)
        button.addTarget(self, action: #selector(selectedDailyButton), for: .touchUpInside)
        view.addSubview(button)

        NSLayoutConstraint.activate([
            button.heightAnchor.constraint(equalToConstant: 30),
            button.widthAnchor.constraint(equalToConstant: 30),
            button.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 100),
            button.topAnchor.constraint(equalTo: view.topAnchor, constant: 100),
            ])
    }
}

这样做。