设置间距时,UIStackView的约束会中断

时间:2017-01-20 11:14:40

标签: ios swift nslayoutconstraint uistackview

当我尝试使用UIStackView时,XCode会抛出以下约束错误:

(
    "<NSAutoresizingMaskLayoutConstraint:0x7f87a1dfa360 h=--& v=--& V:[UIStackView:0x7f87a6403a00(0)]>",
    "<NSLayoutConstraint:0x7f87a6410590 'UISV-canvas-connection' UIStackView:0x7f87a6403a00.top == UIView:0x7f87a6409630.top>",
    "<NSLayoutConstraint:0x7f87a6444170 'UISV-canvas-connection' V:[UIView:0x7f87a644d790]-(0)-|   (Names: '|':UIStackView:0x7f87a6403a00 )>",
    "<NSLayoutConstraint:0x7f87a645bec0 'UISV-fill-equally' UIView:0x7f87a6407a10.height == UIView:0x7f87a6409630.height>",
    "<NSLayoutConstraint:0x7f87a6458f40 'UISV-fill-equally' UIView:0x7f87a644d790.height == UIView:0x7f87a6409630.height>",
    "<NSLayoutConstraint:0x7f87a64306d0 'UISV-spacing' V:[UIView:0x7f87a6409630]-(5)-[UIView:0x7f87a6407a10]>",
    "<NSLayoutConstraint:0x7f87a643bea0 'UISV-spacing' V:[UIView:0x7f87a6407a10]-(5)-[UIView:0x7f87a644d790]>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x7f87a643bea0 'UISV-spacing' V:[UIView:0x7f87a6407a10]-(5)-[UIView:0x7f87a644d790]>

我的视图控制器如下:

public class ExampleController: UIViewController {

    let v1 = UIView(frame: CGRect(x: 0, y: 0, width: 250, height: 100))

    let v2 = UIView(frame: CGRect(x: 0, y: 0, width: 250, height: 300))

    let v3 = UIView(frame: CGRect(x: 0, y: 0, width: 250, height: 200))

    let parent1 = UIStackView()


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

        v1.backgroundColor = .red
        v2.backgroundColor = .green
        v3.backgroundColor = .blue

        parent1.axis = .vertical
        parent1.distribution = .fillEqually
        parent1.spacing = 5 // TODO: This causes the error!

        parent1.addArrangedSubview(v1)
        parent1.addArrangedSubview(v2)
        parent1.addArrangedSubview(v3)

        view.addSubview(parent1)
    }

    // MARK: Constraints

    private var didUpdateConstraints = false

    override public func updateViewConstraints() {
        if !didUpdateConstraints {

            parent1.snp.makeConstraints { (make) -> Void in
                make.edges.equalToSuperview()
            }

            didUpdateConstraints = true
        }
        super.updateViewConstraints()
    }
}

堆栈视图的分布似乎没有什么区别。每当设置间距时,我都会收到错误。

  1. 与我的约束有什么冲突?

  2. 什么是UISV-canvas-connection

3 个答案:

答案 0 :(得分:3)

由于间距,它实际上没有破坏。由于您创建视图的方式,它正在崩溃:D

创建类似...的视图时

let v1 = UIView(frame: CGRect(x: 0, y: 0, width: 250, height: 100))

当视图布局时,它会添加一组默认约束。 UIStackView也是如此。

当你创建它时......

let parent1 = UIStackView()

它得到一个(0,0,0,0)的帧,然后添加约束以保持该帧的位置和高度。

您获得的错误是由于堆栈视图的高度和宽度造成的。

<NSAutoresizingMaskLayoutConstraint:0x7f87a1dfa360 h=--& v=--& V:[UIStackView:0x7f87a6403a00(0)]>

这一行指的是那些“自动”约束。

您最好的选择是使用约束重新创建视图宽度和高度。

喜欢这个......

// using this format means you can create the view and add all the
// other config to it at the same time
let v1: UIView = {
    let u = UIView()

    // this line stops the "automatic" constraints being added
    u.translatesAutoresizingMaskIntoConstraints = false

    u.backgroundColor = .red

    // now you have to add your own constraints though
    u.heightAnchor.constraint(equalToConstant: 100).isActive = true
    u.widthAnchor.constraint(equalToConstant: 250).isActive = true
    return u
}()

let v2: UIView = {
    let u = UIView()
    u.translatesAutoresizingMaskIntoConstraints = false
    u.backgroundColor = .green
    u.heightAnchor.constraint(equalToConstant: 100).isActive = true
    u.widthAnchor.constraint(equalToConstant: 250).isActive = true
    return u
}()

let v3: UIView = {
    let u = UIView()
    u.translatesAutoresizingMaskIntoConstraints = false
    u.backgroundColor = .blue
    u.heightAnchor.constraint(equalToConstant: 100).isActive = true
    u.widthAnchor.constraint(equalToConstant: 250).isActive = true
    return u
}()

let parent1: UIStackView = {
    let s = UIStackView()
    s.translatesAutoresizingMaskIntoConstraints = false
    s.spacing = 5
    s.axis = .vertical
    s.distirbution = .fillEqually
    return s
}()

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

    // I moved all the config stuff into the creation of each view...
    // No need to have them here.

    parent1.addArrangedSubview(v1)
    parent1.addArrangedSubview(v2)
    parent1.addArrangedSubview(v3)

    view.addSubview(parent1)
}

虽然这里有一句警告。

您在堆栈视图中使用.fillEqually。这将使每个视图高度彼此相等。这将与您添加到它们的高度限制冲突。也许你应该完全从每个视图中删除约束,让堆栈视图进行布局。

喜欢这个......

let v2: UIView = {
    let u = UIView()
    u.translatesAutoresizingMaskIntoConstraints = false
    u.backgroundColor = .green
    return u
}()

答案 1 :(得分:3)

我在游乐场测试了它并且它正在工作。您只需将translatesAutoresizingMaskIntoConstraints设置为false并向UIStackView添加约束。

import UIKit
import PlaygroundSupport

public class ExampleController: UIViewController {

    let v1 = UIView(frame: CGRect(x: 0, y: 0, width: 250, height: 100))
    let v2 = UIView(frame: CGRect(x: 0, y: 0, width: 250, height: 300))
    let v3 = UIView(frame: CGRect(x: 0, y: 0, width: 250, height: 200))

    let parent1 = UIStackView()

    public override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .white

        v1.backgroundColor = .red
        v2.backgroundColor = .green
        v3.backgroundColor = .blue

        parent1.axis = .vertical
        parent1.distribution = .fillEqually
        parent1.spacing = 5 // Not causing error

        parent1.addArrangedSubview(v1)
        parent1.addArrangedSubview(v2)
        parent1.addArrangedSubview(v3)

        parent1.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(parent1)

        NSLayoutConstraint.activate([
            parent1.topAnchor.constraint(equalTo: view.topAnchor),
            parent1.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            parent1.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            parent1.bottomAnchor.constraint(equalTo: view.bottomAnchor),
        ])
    }

}

PlaygroundPage.current.liveView = ExampleController()

结果:

enter image description here

答案 2 :(得分:2)

我遇到了同样的问题。对我来说,诀窍是在设置约束之前将UIStackView的间距设置为0。设置约束后,我将间距设置为所需的量。这清除了冲突的约束。