NSLayoutConstraint 的幽灵困扰着我的视图层次结构?

Posted

技术标签:

【中文标题】NSLayoutConstraint 的幽灵困扰着我的视图层次结构?【英文标题】:The ghost of NSLayoutConstraint haunts my view hierarchy? 【发布时间】:2015-01-03 23:28:17 【问题描述】:

我正在尝试以编程方式修改自动布局约束以向上移动表格视图,但仅适用于处于横向模式的 iPhone 6 Plus,因为我无法在使用 Xcode 6.2 beta 3 的所有设备上实现我想要的精确视觉效果Interface Builder 的自动布局(从 IB 获得,用于其他支持的设备/方向。只是 iPhone 6 Plus 在 iPhone 和 iPad 之间有点离群,因此有点棘手)

我删除的一个约束 似乎 在删除后会被删除(例如,从包含视图的约束中消失,正如预期的那样),但是,布局管理器 still 似乎找到了它并警告它与其他约束冲突,并在运行时打破约束,幸运的结果是应用程序产生了预期的视觉结果,但不幸的是,我想修复丑陋的控制台警告消息的副作用,因为它是丑陋的 Apple 文档将此类警告归咎于用户代码错误。

我的代码拦截了方向变化(仅在 iPhone 6 Plus 上), 然后:

=============

• 在 tableview 的所有者视图中迭代约束

• 打印具有 .Top 属性的任何约束的属性

• 删除通过 IBOutlet 引用的用于 tableview 的 Center Y 约束

• 使用 .Top 属性移除约束

• 添加具有不同乘数的新 .Top 属性

============

这是我的视图控制器中的 swift 代码:

    override func willRotateToInterfaceOrientation(toInterfaceOrientation: UIInterfaceOrientation, duration: NSTimeInterval) 
        switch(toInterfaceOrientation) 
        case .LandscapeLeft:
            fallthrough
        case .LandscapeRight:
            var deviceType = UIDevice().deviceType

            if (deviceType == .iPhone6plus || deviceType == .simulator) 
                if centerYconstraint != nil 
                    self.view.removeConstraint(centerYconstraint)
                    centerYconstraint = nil
                    for constraint in self.view.constraints() 
                        if (constraint.firstItem as NSObject == self.tableView) 
                            if (constraint.firstAttribute == NSLayoutAttribute.Top) 
                                println("found item \(constraint)")
                                let view1 = constraint.firstItem as UIView
                                let attr1 = constraint.firstAttribute
                                let view2 = constraint.secondItem as UIView
                                let attr2 = constraint.secondAttribute
                                let relation = constraint.relation
                                let constant = constraint.constant
                                let newConstraint = NSLayoutConstraint(
                                    item:       view1,
                                    attribute:  attr1,
                                    relatedBy:  relation,
                                    toItem:     view2,
                                    attribute:  attr2,
                                    multiplier: 0.02,
                                    constant:   constant)
                                self.view.removeConstraint(constraint as NSLayoutConstraint)
                                self.view.addConstraint(newConstraint)
                                self.view.layoutIfNeeded()
                            
                        
                    
                
            
        default:
            break
        
    

这是 Xcode 模拟器的输出。注意我打印删除的约束的第一行“找到的项目”。

但是您可以在布局管理器随后抱怨的潜在冲突列表中看到 相同 view1 和 view2、乘数和属性。这就是我感到困惑的地方。

found item <NSLayoutConstraint:0x7f8a05101bb0 UITableView:0x7f8a05853000.top == 0.03*_UILayoutGuide:0x7f8a035517e0.top>


2015-01-03 14:36:35.290 Interphase[46388:74323123] 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. (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints) 
(
    "<NSLayoutConstraint:0x7f8a0354da40 V:[UITableView:0x7f8a05853000(336)]>",
    "<_UILayoutSupportConstraint:0x7f8a0514df70 V:[_UILayoutGuide:0x7f8a035517e0(49)]>",
    "<_UILayoutSupportConstraint:0x7f8a051908e0 _UILayoutGuide:0x7f8a035517e0.bottom == UIView:0x7f8a03551480.bottom>",
    "<NSLayoutConstraint:0x7f8a051b53d0 'UIView-Encapsulated-Layout-Height' V:[UIView:0x7f8a03551480(414)]>",
    "<NSLayoutConstraint:0x7f8a050d9080 UITableView:0x7f8a05853000.top == 0.02*_UILayoutGuide:0x7f8a035517e0.top>",
    "<NSLayoutConstraint:0x7f8a0354ef80 UITableView:0x7f8a05853000.centerY == UIView:0x7f8a03551480.centerY>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x7f8a0354da40 V:[UITableView:0x7f8a05853000(336)]>

Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.
2015-01-03 14:36:56.720 Interphase[46388:74323123] 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. (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints) 
(
    "<_UILayoutSupportConstraint:0x7f8a0514df70 V:[_UILayoutGuide:0x7f8a035517e0(49)]>",
    "<_UILayoutSupportConstraint:0x7f8a051908e0 _UILayoutGuide:0x7f8a035517e0.bottom == UIView:0x7f8a03551480.bottom>",
    "<NSLayoutConstraint:0x7f8a05101bb0 UITableView:0x7f8a05853000.top == 0.03*_UILayoutGuide:0x7f8a035517e0.top>",
    "<NSLayoutConstraint:0x7f8a051b53d0 'UIView-Encapsulated-Layout-Height' V:[UIView:0x7f8a03551480(736)]>",
    "<NSLayoutConstraint:0x7f8a050d9080 UITableView:0x7f8a05853000.top == 0.02*_UILayoutGuide:0x7f8a035517e0.top>"
)

【问题讨论】:

【参考方案1】:

向视图添加和删除约束有点不稳定。永远不清楚应该将它们添加到哪个视图,然后当您想要删除它时很难找到它。

更好的解决方案是保留对您关心的约束的引用(如果您是从界面生成器执行此操作,则作为出口,或者只是将它们存储在属性中),然后 activate 或将它们停用为必需的。

激活约束而不是添加它们也可以防止您必须决定将它们添加到哪个视图 - 系统会自动执行此操作。

【讨论】:

至于第一部分 - 很明显,感兴趣的约束最终属于的视图,因为它们是在 IB 中创建的,它显示了它们所属的视图。在我的情况下,它们没有被激活,检查它们的激活时间是时候弄乱它们了。在这个线程中检查我对我的问题的回答,了解这个技巧是如何工作的。就您提到的列表/激活想法而言,对于完全以编程方式管理其布局的应用程序来说,这是一个很好的建议!

以上是关于NSLayoutConstraint 的幽灵困扰着我的视图层次结构?的主要内容,如果未能解决你的问题,请参考以下文章

听着好像很牛的特效——幽灵按钮DOM

困扰爱因斯坦的难题如何被证明?

困扰爱因斯坦的难题如何被证明?

幽灵按钮的实现

幽灵按键

MMSID分享-1