添加子视图可以更改每个约束

问题描述 投票:0回答:1

我在我的项目中尝试做的是根据来自 firebase 的位置数据(例如 x = 5,y = 10,宽度 = 30,高度 = 50)将图像传输到屏幕。例如,假设我有 10 张图像要显示(甚至可能有 100 张图像)。这些图像中的第一个应该在顶部。每个传入图像必须低于前一个图像,但图像在 x 和 y 轴上可以不同。我试图用 for 循环将不同的约束分配给我只定义了一个的图像。但我的问题是出现以下约束错误。你能帮我怎么做吗?应该是如下图。  The image hereMy simulator shows only one view like this image.

错误:

[LayoutConstraints] Unable to simultaneously satisfy constraints.
    Probably at least one of the constraints in the following list is one you don't want. 
    Try this: 
        (1) look at each constraint and try to figure out which you don't expect; 
        (2) find the code that added the unwanted constraint or constraints and fix it. 
(
    "<NSLayoutConstraint:0x600000cd4dc0 UIView:0x12b304a70.height == 50   (active)>",
    "<NSLayoutConstraint:0x600000cd51d0 V:[UIView:0x12b304a70]-(60)-[UIView:0x12b304a70]   (active)>"
)

我的代码:

let View: UIView = {
    let view = UIView()
    view.backgroundColor = .red
    view.translatesAutoresizingMaskIntoConstraints = false
    return view
}()

var count = 1
var topAnchor: NSLayoutYAxisAnchor?
for views in 1...11{
    if count == 1{
        view.addSubview(View)
        View.anchor(top: view.safeAreaLayoutGuide.topAnchor, bottom: nil, leading: nil, trailing: nil, paddingTop: 10, paddingBottom: 0, paddingLeft: 0, paddingRight: 0, width: 50, height: 50)
        View.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
        topAnchor = View.bottomAnchor
        count += 1
    }
    else{ // if count
        view.addSubview(View)
        View.anchor(top: topAnchor, bottom: nil, leading: nil, trailing: nil, paddingTop: 60, paddingBottom: 0, paddingLeft: 0, paddingRight: 0, width: 30, height: 30)
        View.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
        topAnchor = View.topAnchor
    }
}

有了这个扩展:

extension UIView{
    func anchor(top: NSLayoutYAxisAnchor?,
                bottom: NSLayoutYAxisAnchor?,
                leading: NSLayoutXAxisAnchor?,
                trailing: NSLayoutXAxisAnchor?,
                paddingTop: CGFloat,
                paddingBottom: CGFloat,
                paddingLeft: CGFloat,
                paddingRight: CGFloat,
                width: CGFloat,
                height: CGFloat
    ){
        if let top = top{
            self.topAnchor.constraint(equalTo: top, constant: paddingTop).isActive = true
        }
        if let bottom = bottom{
            self.bottomAnchor.constraint(equalTo: bottom, constant: paddingBottom).isActive = true
        }
        if let leading = leading{
            self.leadingAnchor.constraint(equalTo: leading, constant: paddingLeft).isActive = true
        }
        if let trailing = trailing{
            self.trailingAnchor.constraint(equalTo: trailing, constant: paddingRight).isActive = true
        }
        if width != 0{
            widthAnchor.constraint(equalToConstant: width).isActive = true
        }
        if height != 0{
            heightAnchor.constraint(equalToConstant: height).isActive = true
        }
    }
}
ios swift uiview nslayoutconstraint subview
1个回答
0
投票

一些观察:

  1. 正如 Geoff Hackworth 指出的那样,您只创建了一个子视图(一个使用闭包实例化过一次的子视图)。你真的想要一个每次都创建一个新子视图的方法。

  2. else
    闭包中,您将每个后续视图的顶部锚点设置为前一个视图的顶部锚点。您可能想将下一个视图的顶部锚点设置为相对于前一个视图的底部锚点。

  3. 作为一个小细节,您没有设置最后一个视图的底部锚点。通常我们希望我们的约束被完全定义,所以我建议为最后一个子视图添加一个

    bottomAnchor
    (即使它是一个≥锚点)。

所以,也许:

func createView() -> UIView {
    let view = UIView()
    view.backgroundColor = .red
    view.translatesAutoresizingMaskIntoConstraints = false
    return view
}

func addSubviews() {
    var topAnchor: NSLayoutYAxisAnchor = view.safeAreaLayoutGuide.topAnchor
    var subview: UIView!
    for index in 1...11 {
        subview = createView()
        view.addSubview(subview)
        subview.addAnchors(top: topAnchor, paddingTop: 10, width: 50, height: 50)
        subview.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
        topAnchor = subview.bottomAnchor
    }
    view.bottomAnchor.constraint(greaterThanOrEqualTo: subview.bottomAnchor, constant: 10).isActive = true
}

而且,如果你原谅我,我调整了

UIView
扩展:

extension UIView{
    func addAnchors(
        top: NSLayoutYAxisAnchor? = nil,
        bottom: NSLayoutYAxisAnchor? = nil,
        leading: NSLayoutXAxisAnchor? = nil,
        trailing: NSLayoutXAxisAnchor? = nil,
        paddingTop: CGFloat = 0,
        paddingBottom: CGFloat = 0,
        paddingLeft: CGFloat = 0,
        paddingRight: CGFloat = 0,
        width: CGFloat? = nil,
        height: CGFloat? = nil
    ) {
        if let top {
            topAnchor.constraint(equalTo: top, constant: paddingTop).isActive = true
        }
        if let bottom {
            bottomAnchor.constraint(equalTo: bottom, constant: paddingBottom).isActive = true
        }
        if let leading {
            leadingAnchor.constraint(equalTo: leading, constant: paddingLeft).isActive = true
        }
        if let trailing {
            trailingAnchor.constraint(equalTo: trailing, constant: paddingRight).isActive = true
        }
        if let width {
            widthAnchor.constraint(equalToConstant: width).isActive = true
        }
        if let height {
            heightAnchor.constraint(equalToConstant: height).isActive = true
        }
    }
}

在上面,我还有:

  1. 简化了

    for
    循环,因此我们不需要基于计数器的
    if
    -
    else

  2. 我已经为它的参数提供了

    UIView
    扩展的默认值,所以你不需要在调用点提供
    nil
    的参数。

© www.soinside.com 2019 - 2024. All rights reserved.