为什么 NSLayoutConstraints 标识符 属性 在代码中不起作用?

Why is NSLayoutConstraint's identifier property not working in code?

我正在尝试编写一些不添加两次相同约束的条件。例如,如果视图已经具有底部锚点约束,则不要再次添加它。所以我尝试使用布局约束标识符来唯一标识一个约束,这样如果它已经存在就不要再添加另一个约束。我没有故事板,所以我写了下面的代码:

class PDFViewer: UIViewController {
     var quickLookController = QLPreviewController()
    
     override func viewDidLoad()

     if let quickView = quickLookController.view {
            self.view.addSubview(quickView)
     }

     {
        quickLookController.view.translatesAutoresizingMaskIntoConstraints = false
        quickLookController.view.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
        quickLookController.view.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
        quickLookController.view.topAnchor.constraint(equalTo: navView.bottomAnchor).isActive = true
        
        setPDFViewHeight(height: 100)
        setPDFViewHeight(height: 100)

    }
    
    open func setPDFViewHeight(height: CGFloat) {
        
        var isBottomAnchorSet = false
        
        if let superView = quickLookController.view.superview {
            for constraints in superView.constraints {
                if constraints.identifier == "bottom" {
                    isBottomAnchorSet = true
                }
                else {
                    print(false)
                }
            }
        }
        
        if !isBottomAnchorSet {
            quickLookController.view.bottomAnchor.constraint(equalTo: view.bottomAnchor).identifier = "bottom"
            quickLookController.view.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
        }
    }
}

但是我两次调用 setPDFViewHeight 方法时它都说没有名为 "bottom" 的标识符,但第二次应该是。我也试过像下面这样直接获取超级​​视图的约束,但那里也有同样的问题。

        for constraints in view.constraints {
            if constraints.identifier == "bottom" {
                isBottomAnchorSet = true
            }
        }

我做错了什么或者这个标识符不能这样使用?

即使是关于如何避免布局约束重复的完全不同的答案也会有所帮助。提前致谢。

我认为在您的情况下,最好保留底部约束并稍后在需要时更新常量,如下所示:

class PDFViewer: UIViewController {
     var quickLookController = QLPreviewController()
     var bottomConstraint: NSLayoutConstraint?
    
     override func viewDidLoad()

     if let quickView = quickLookController.view {
            self.view.addSubview(quickView)
     }

     quickLookController.view.translatesAutoresizingMaskIntoConstraints = false
     bottomConstraint = quickLookController.view.bottomAnchor.constraint(equalTo: view.bottomAnchor)
     NSLayoutConstraint.activate([
        quickLookController.view.leadingAnchor.constraint(equalTo: view.leadingAnchor),
        quickLookController.view.trailingAnchor.constraint(equalTo: view.trailingAnchor),
        quickLookController.view.topAnchor.constraint(equalTo: navView.bottomAnchor),
        bottomConstraint
     ])
        
     setPDFViewHeight(height: 100)
     setPDFViewHeight(height: 100)

    
    open func setPDFViewHeight(height: CGFloat) {
        bottomConstraint.constant = height
    }
}

此外 setPDFViewHeight 的命名可能会产生误导,因为它真正做的是设置距锚点的偏移量,而不是绝对高度。

问题是您正在创建两个底部约束:

// this creates a constraint
//  with an identifier
//  but does not activate it
quickLookController.view.bottomAnchor.constraint(equalTo: view.bottomAnchor).identifier = "bottom"

// this creates a constraint
//  WITHOUT an identifier
//  and activates it
quickLookController.view.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true

试一试:

open func setPDFViewHeight(height: CGFloat) {
    
    var isBottomAnchorSet = false

    if let superView = quickLookController.view.superview {
        for constraint in superView.constraints {
            print("constraint identifier:", constraint.identifier ?? "no id", constraint)
            if constraint.identifier == "bottom" {
                isBottomAnchorSet = true
                print("Bottom Anchor already set")
            }
        }
        if !isBottomAnchorSet {
            print("Creating Bottom Anchor")
            let c = quickLookController.view.bottomAnchor.constraint(equalTo: view.bottomAnchor)
            c.identifier = "bottom"
            c.isActive = true
        }
    }

}

要对其进行测试,请将您的双重调用替换为:

print("First call")
print()
setPDFViewHeight(height: 100)

print()
print("Second call")
print()
setPDFViewHeight(height: 100)
    

这是我得到的输出:

First call

constraint identifier: no id <NSLayoutConstraint:0x600002086030 H:|-(0)-[UIView:0x7fbfa5407fa0]   (active, names: '|':UIView:0x7fbfa54084d0 )>
constraint identifier: no id <NSLayoutConstraint:0x600002085fe0 UIView:0x7fbfa5407fa0.trailing == UIView:0x7fbfa54084d0.trailing   (active)>
constraint identifier: no id <NSLayoutConstraint:0x600002085f40 V:|-(0)-[UIView:0x7fbfa5407fa0]   (active, names: '|':UIView:0x7fbfa54084d0 )>
Creating Bottom Anchor

Second call

constraint identifier: no id <NSLayoutConstraint:0x600002086030 H:|-(0)-[UIView:0x7fbfa5407fa0]   (active, names: '|':UIView:0x7fbfa54084d0 )>
constraint identifier: no id <NSLayoutConstraint:0x600002085fe0 UIView:0x7fbfa5407fa0.trailing == UIView:0x7fbfa54084d0.trailing   (active)>
constraint identifier: no id <NSLayoutConstraint:0x600002085f40 V:|-(0)-[UIView:0x7fbfa5407fa0]   (active, names: '|':UIView:0x7fbfa54084d0 )>
constraint identifier: bottom <NSLayoutConstraint:0x60000208bc00 'bottom' UIView:0x7fbfa5407fa0.bottom == UIView:0x7fbfa54084d0.bottom   (active)>
Bottom Anchor already set