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

时间:2019-03-07 19:45:23

标签: ios swift autolayout uikit

我有以下代码适用于高度和宽度约束。尝试添加前导约束和上限约束时会崩溃。我还有其他具有高度,宽度,前导和顶部约束的按钮集,但是它们都设置在情节提要板上,因此我认为这些是我必须添加到每个按钮的唯一4个约束。

我有7个按钮,每个按钮在一周的某一天。当我添加代码来执行前导约束和顶部约束时,它会与以下错误代码一起破坏。高度/宽度都可以正常工作。我猜想这与我向视图控制器添加子视图或按钮关系的方式有关,或者以编程方式进行时,我需要的不止是我一直使用的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 每日[27852:1408014] [LayoutConstraints]没有为约束准备视图层次结构:     当添加到视图时,约束的项必须是该视图的后代(或视图本身)。如果在组装视图层次结构之前需要解决约束,则会崩溃。中断-[UIView(UIConstraintBasedLayout)_viewHierarchyUnpreparedForConstraint:]进行调试。

2019-03-07 14:38:59.177816-0500每日[27852:1408014] [LayoutConstraints]视图层次结构未准备好进行约束。     约束:     容器层次结构: >    | >     在容器层次结构中找不到视图:>     该视图的超级视图:无超级视图

2019-03-07 14:38:59.192176-0500 Daily [27852:1408014] ***由于未捕获的异常'NSGenericException'终止了应用程序,原因:'无法在视图上安装约束。约束是否引用了视图子树之外的内容?那是非法的。约束:视图:>'

2 个答案:

答案 0 :(得分:0)

已经有一段时间了,因为我已经在代码中添加了约束,但是如果有内存,则必须在添加约束之前将视图添加到视图层次结构中。 (这就是错误消息的提示。)

答案 1 :(得分:0)

        self.weeklyButtons[i].addConstraint(leadingConstraint)

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

  

添加到视图时,约束的项必须是该视图(或视图本身)的后代。

由于self.viewweeklyButtons[i]的超级视图,因此它被视为这两个视图的共同祖先。因此,在这种情况下,您可以将约束添加到self.view

self.view.addConstraint(leadingConstraint)

但是不要这样做。从iOS 8开始,您可以直接激活约束,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),
            ])
    }
}

这样做。