【问题标题】:Why is NSLayoutConstraint's identifier property not working in code?为什么 NSLayoutConstraints 标识符属性在代码中不起作用?
【发布时间】:2020-09-30 10:29:48
【问题描述】:

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

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
            }
        }

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

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

【问题讨论】:

    标签: ios swift xcode nslayoutconstraint


    【解决方案1】:

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

    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 的命名也可能会产生误导,因为它真正的作用是设置与锚点的偏移量,而不是绝对高度。

    【讨论】:

    • 我是否应该在每次调用setPDFViewHeight() 时也调用layoutSubviews()?。我已经在函数名称中注明了您的观点。会想出一个更正确的。谢谢
    • @RohithS 不要直接调用layoutSubviews(),而是调用layoutIfNeeded()。您可以在这篇精彩的文章medium.com/@abhimuralidharan/… 中了解更多关于差异的信息
    • 谢谢。做到了!
    【解决方案2】:

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

    // 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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-11-19
      • 2017-03-17
      • 2021-11-17
      • 1970-01-01
      • 2021-11-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多