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

标签 ios swift autolayout uikit

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

我有 7 个按钮,每个按钮代表一周中的一天。当我添加代码来执行前导和顶部约束时,它会因下面的错误代码而中断。仅使用高度/宽度即可正常工作。我猜这与我添加 subview 的方式或按钮与 View Controller 的关系有关,或者以编程方式执行时我需要的不仅仅是我一直在使用的 4 个约束(前导、顶部、宽度、高度)在 Storyboard上。

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 激活约束,则必须将约束添加到两个 View 的共同祖先。这就是此错误消息告诉您的内容:

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

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

self.view.addConstraint(leadingConstraint)

但不要这样做。从 iOS 8 开始,您可以直接激活约束,UIKit 会自动将其添加到正确的 View 中:

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),
            ])
    }
}

这样做。

关于ios - 以编程方式添加前导/顶部约束,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55051717/

相关文章:

iOS - 核心动画 - 如何在变换属性更改时设置原点

android - 使用配置文件发布移动(React Native) Artifact

ios - 使用解密时,表达式类型不明确,没有更多 AES 上下文

ios - 在 iOS8+ 上使用 AutoLayout 的自定大小的 TableView 单元格内的可变高度 CollectionView

ios - 如何在底部插入带有动画的 UITableViewCell?

ios - 代码中的自动布局?高度问题?

ios - 将 UIPickerView 放置在 UIAlertController 的中心

ios - 在 Tableview 中,如何在 Objective C 中获取选定行的 textview 值

IOS13+ NSPersistentCloudKitContainer UIRefreshControl 如何刷新UITableView内容

iOS - 如何在不同的 UITableViewCell 中重新使用 UIView