简体   繁体   English

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

[英]adding leading / top constraints programmatically

I have the following code working for the height and width constraints.我有以下代码适用于高度和宽度约束。 It crashes when trying to add the leading constraint and the top constraint.尝试添加前导约束和顶部约束时它会崩溃。 I have other sets of buttons that have height, width, leading, top constraints but they were all set up on the storyboard, so I figure these are the only 4 constraints I MUST add to each button.我还有其他具有高度、宽度、前导、顶部约束的按钮组,但它们都设置在故事板上,所以我认为这些是我必须添加到每个按钮的仅有的 4 个约束。

I have 7 buttons, each for a day of the week.我有 7 个按钮,每个按钮用于一周中的一天。 When I add the code to do the leading and top constraints it breaks with the error code below.当我添加代码来执行前导和顶部约束时,它会因下面的错误代码而中断。 It works fine with just height/width.它仅适用于高度/宽度。 I'm guessing it has to do with the way I'm adding subviews or the relationship of the buttons to the view controller OR when doing programmatically I need more than the 4 constraints (leading, top, width, height) I have been using on storyboard.我猜这与我添加子视图的方式或按钮与视图控制器的关系有关,或者在以编程方式执行时,我需要的约束超过我一直使用的 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). 2019-03-07 14:38:59.176638-0500 Daily[27852:1408014] [LayoutConstraints] 未为约束准备视图层次结构:添加到视图时,约束的项必须是该视图(或视图)的后代本身)。 This will crash if the constraint needs to be resolved before the view hierarchy is assembled.如果在组装视图层次结构之前需要解决约束,这将崩溃。 Break on -[UIView(UIConstraintBasedLayout) _viewHierarchyUnpreparedForConstraint:] to debug.中断 -[UIView(UIConstraintBasedLayout) _viewHierarchyUnpreparedForConstraint:] 进行调试。

2019-03-07 14:38:59.177816-0500 Daily[27852:1408014] [LayoutConstraints] View hierarchy unprepared for constraint. 2019-03-07 14:38:59.177816-0500 Daily[27852:1408014] [LayoutConstraints] 视图层次结构没有准备好约束。 Constraint: Container hierarchy: > |约束:容器层次结构:> | > View not found in container hierarchy: > That view's superview: NO 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. 2019-03-07 14:38:59.192176-0500 Daily[27852:1408014] *** 由于未捕获的异常“NSGenericException”而终止应用程序,原因:“无法在视图上安装约束。 Does the constraint reference something from outside the subtree of the view?约束是否引用了视图子树之外的内容? That's illegal.那是非法的。 constraint: view:>'约束:视图:>'

It's been a while since I've added constraints in code, but if memory serves you have to add the views to the view hierarchy before adding constraints.自从我在代码中添加约束以来已经有一段时间了,但是如果没有记错,您必须在添加约束之前将视图添加到视图层次结构中。 (That's what the error message suggests.) (这就是错误消息所暗示的。)

 self.weeklyButtons[i].addConstraint(leadingConstraint)

The constraint involves weeklyButtons[i] and self.view .约束涉及weeklyButtons[i]self.view If you use addConstraint to activate the constraint, you have to add the constraint to a common ancestor of the two views.如果使用addConstraint激活约束,则必须将约束添加到两个视图的共同祖先。 That is what this error message is telling you:这就是此错误消息告诉您的内容:

When added to a view, the constraint's items must be descendants of that view (or the view itself).添加到视图时,约束的项必须是该视图(或视图本身)的后代。

Since self.view is the superview of weeklyButtons[i] , it counts as a common ancestor of the two views.由于self.viewweeklyButtons[i]weeklyButtons[i]视图,它算作两个视图的共同祖先。 So in this case, you can add the constraint to self.view :因此,在这种情况下,您可以将约束添加到self.view

self.view.addConstraint(leadingConstraint)

But don't do that.但不要那样做。 Since iOS 8, you can activate a constraint directly, and UIKit will add it to the correct view automatically:从 iOS 8 开始,你可以直接激活一个约束,UIKit 会自动将它添加到正确的视图中:

leadingConstraint.isActive = true

But don't do that.但不要那样做。 Since you are adding four constraints in succession, it may be slightly more efficient to activate the four constraints all at once like this:由于您要连续添加四个约束,因此像这样同时激活四个约束可能会更有效:

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

But don't do that.但不要那样做。 Since iOS 9, there has been a much more readable way to create constraints:从 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),
    ])

But don't do that.但不要那样做。 Use a for / in loop instead of index variable i :使用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),
            ])
    }
}

Do that.去做。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM