冲突约束(不存在)(Swift 4)

Posted

技术标签:

【中文标题】冲突约束(不存在)(Swift 4)【英文标题】:Conflicting Constraints (that do not exist) (Swift 4) 【发布时间】:2020-10-10 18:34:54 【问题描述】:

当手机旋转时,我正在重新排列三个视图:

我设置约束如下:

    var narrowConstraints: [NSLayoutConstraint] = []
    var wideConstraints: [NSLayoutConstraint] = []

    func setConstraints1() 
        
        let cv1Height: CGFloat = 325
        let cv3Height: CGFloat = 125
        
        cv1.translatesAutoresizingMaskIntoConstraints = false
        cv2.translatesAutoresizingMaskIntoConstraints = false
        cv3.translatesAutoresizingMaskIntoConstraints = false
        
        let g = view.safeAreaLayoutGuide
        
        // wh
        narrowConstraints = [
            
            // set cv1 height
            cv1.heightAnchor.constraint(equalToConstant: cv1Height),
            // lock top, left and right to safe area
            cv1.topAnchor.constraint(equalTo: g.topAnchor),
            cv1.leadingAnchor.constraint(equalTo: g.leadingAnchor),
            cv1.trailingAnchor.constraint(equalTo: g.trailingAnchor),

            // lock left and right to safe area
            cv2.leadingAnchor.constraint(equalTo: g.leadingAnchor),
            cv2.trailingAnchor.constraint(equalTo: g.trailingAnchor),
            
            // lock top of cv2 to bottom of cv1
            cv2.topAnchor.constraint(equalTo: cv1.bottomAnchor),
            // lock bottom of cv2 to top of cv3
            cv2.bottomAnchor.constraint(equalTo: cv3.topAnchor),
            
            // set cv3 height
            cv3.heightAnchor.constraint(equalToConstant: cv3Height),
            // lock left, right and bottom to safe area
            cv3.leadingAnchor.constraint(equalTo: g.leadingAnchor),
            cv3.trailingAnchor.constraint(equalTo: g.trailingAnchor),
            cv3.bottomAnchor.constraint(equalTo: g.bottomAnchor),
        ]
        
        wideConstraints = [

            // lock top, bottom, and left to safe area
            cv1.topAnchor.constraint(equalTo: g.topAnchor),
            cv1.bottomAnchor.constraint(equalTo: g.bottomAnchor),
            cv1.leadingAnchor.constraint(equalTo: g.leadingAnchor),
            // lock right side of cv1 to left side of cv2
            cv1.trailingAnchor.constraint(equalTo: cv2.leadingAnchor),
            
            // lock right side of cv2 to safe area
            cv2.trailingAnchor.constraint(equalTo: g.trailingAnchor),
            // lock top of cv2 to safe area
            cv2.topAnchor.constraint(equalTo: g.topAnchor),
            // lock bottom of cv2 to top of cv3
            cv2.bottomAnchor.constraint(equalTo: cv3.topAnchor),

            // set cv3 height
            cv3.heightAnchor.constraint(equalToConstant: cv3Height),
            // lock bottom and right side of cv3 to safe area
            cv3.trailingAnchor.constraint(equalTo: g.trailingAnchor),
            cv3.bottomAnchor.constraint(equalTo: g.bottomAnchor),
            
            // make them all equal widths
            cv2.widthAnchor.constraint(equalTo: cv1.widthAnchor),
            cv3.widthAnchor.constraint(equalTo: cv2.widthAnchor),            
        ]
        
        if view.frame.width > view.frame.height 
            // if landscape
            NSLayoutConstraint.deactivate(narrowConstraints)
            NSLayoutConstraint.activate(wideConstraints)
        
        else  // portrait
            NSLayoutConstraint.deactivate(wideConstraints)
            NSLayoutConstraint.activate(narrowConstraints)
        
    

    override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) 
        super.viewWillTransition(to: size, with: coordinator)
        coordinator.animate(alongsideTransition:  _ in
            if size.width > size.height 
                // we're transitioning to wider than tall
                NSLayoutConstraint.deactivate(self.narrowConstraints)
                NSLayoutConstraint.activate(self.wideConstraints)
             else 
                // we're transitioning to taller than wide
                NSLayoutConstraint.deactivate(self.wideConstraints)
                NSLayoutConstraint.activate(self.narrowConstraints)
            
        , completion: 
            _ in
            // if you want to do something after the transition
            //self.cv2.setNeedsDisplay()
        )
    

一切似乎都运行良好 - 除了以下错误消息:

2020-10-16 14:33:57.364778-0600 ViewPositions2[38358:6108060] [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:0x6000033a9130 UIView:0x7fb41950ad90.height == 325   (active)>",
    "<NSLayoutConstraint:0x6000033aa800 UIView:0x7fb41950ad90.top == UILayoutGuide:0x6000029bcb60'UIViewSafeAreaLayoutGuide'.top   (active)>",
    "<NSLayoutConstraint:0x6000033aa3f0 V:[UIView:0x7fb41950ad90]-(0)-[UIView:0x7fb41950dec0]   (active)>",
    "<NSLayoutConstraint:0x6000033a9ea0 UIView:0x7fb41950dec0.bottom == UIView:0x7fb41950e8f0.top   (active)>",
    "<NSLayoutConstraint:0x6000033a9c70 UIView:0x7fb41950e8f0.height == 125   (active)>",
    "<NSLayoutConstraint:0x6000033aa2b0 UIView:0x7fb41950e8f0.bottom == UILayoutGuide:0x6000029bcb60'UIViewSafeAreaLayoutGuide'.bottom   (active)>",
    "<NSLayoutConstraint:0x60000339ff20 'UIView-Encapsulated-Layout-Height' UIView:0x7fb41950f1c0.height == 375   (active)>",
    "<NSLayoutConstraint:0x60000339b840 'UIViewSafeAreaLayoutGuide-bottom' V:[UILayoutGuide:0x6000029bcb60'UIViewSafeAreaLayoutGuide']-(0)-|   (active, names: '|':UIView:0x7fb41950f1c0 )>",
    "<NSLayoutConstraint:0x60000339b7a0 'UIViewSafeAreaLayoutGuide-top' V:|-(0)-[UILayoutGuide:0x6000029bcb60'UIViewSafeAreaLayoutGuide']   (active, names: '|':UIView:0x7fb41950f1c0 )>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x6000033a9130 UIView:0x7fb41950ad90.height == 325   (active)>

经过反复试验,我发现如果cv1Heightcv2Height 的总和超过375(横向视图高度),则会出现此错误消息。

但是,我不仅在横屏时停用了narrowConstraints,而且在横屏时cv1 永远不会在cv3 之上!

为什么会发生这种冲突?怎么预防???

【问题讨论】:

【参考方案1】:

冲突是由于过渡期间状态栏的出现引起的。虽然您可以忽略警告(它不会影响应用的操作或外观),但可以通过降低纵向配置中 cv1 高度约束的优先级来消除警告:

let h1 = cv1.heightAnchor.constraint(equalToConstant: cv1Height)
h1.priority = .defaultHigh
            
narrowConstraints = [
                // set cv1 height
    h1,
                // lock top, left and right to safe area
    cv1.topAnchor.constraint(equalTo: g.topAnchor),
    cv1.leadingAnchor.constraint(equalTo: g.leadingAnchor),
    cv1.trailingAnchor.constraint(equalTo: g.trailingAnchor),

                // lock left and right to safe area
    cv2.leadingAnchor.constraint(equalTo: g.leadingAnchor),
    cv2.trailingAnchor.constraint(equalTo: g.trailingAnchor),
                
                // lock top of cv2 to bottom of cv1
    cv2.topAnchor.constraint(equalTo: cv1.bottomAnchor),
                // lock bottom of cv2 to top of cv3
    cv2.bottomAnchor.constraint(equalTo: cv3.topAnchor),
                
                // set cv3 height
    cv3.heightAnchor.constraint(equalToConstant: cv3Height),
                // lock left, right and bottom to safe area
    cv3.leadingAnchor.constraint(equalTo: g.leadingAnchor),
    cv3.trailingAnchor.constraint(equalTo: g.trailingAnchor),
    cv3.bottomAnchor.constraint(equalTo: g.bottomAnchor),
]

【讨论】:

令人着迷,船长。我们应该将其视为错误吗? 也许这只是 AutoLayout 的迷人特质之一? 好吧,我建议 OP 应该报告它。就像那些关于警报和工具栏的虚假冲突报告一样,令人抓狂 是的。创建minimal reproducible example 并不难,值得举报 @Paulw11 - 我刚刚发布了另一个似乎相关的问题:***.com/questions/64539800/… 这也是一个错误吗?

以上是关于冲突约束(不存在)(Swift 4)的主要内容,如果未能解决你的问题,请参考以下文章

Swift 包中的 XIB 文件 - 忽略约束

说说发现 Jar 包存在冲突的方法

以编程方式设置约束导致 Swift 中的冲突

使用 getenv 检索不存在的环境变量时出现访问冲突异常

java多线程访问同一个数组,存在并发问题吗,每个线程访问的是数组的不同部分,不存在冲突

尽管记录不存在,但 SQL 主键约束