哪个布局约束优先于同等优先级?

Which layout constraint precedes with equal priority?

给定两个约束:

NSLayoutConstraint.activate([
    aView.topAnchor.constraint(equalTo: cView.topAnchor) //#1
    aView.topAnchor.constraint(greaterThanOrEqualTo: bView.bottomAnchor, constant: 10) //#2
    ])

让我们假设约束 #1 中的 cView.topAnchor 小于(即 "further up north")约束 #2 中的 bView.bottomAnchor

这不应该导致自动布局冲突吗,因为它不能满足两个约束,因为它们具有相同的优先级?

奇怪的是它没有 - 至少不在日志 window 中,也不在 Xcode 的调试视图层次结构中。

我的方法是将约束 #1 的优先级设置为 .defaultHigh,以便自动布局可以打破约束而不会发生冲突。

难道还需要设置优先级吗,好像没什么冲突?

基于文档的解释

具有相同优先级的两个(或多个)约束不能同时满足总是会导致冲突。根据 documentation:

When the system detects a unsatisfiable layout at runtime, it performs the following steps:

  1. Auto Layout identifies the set of conflicting constraints.

  2. It breaks one of the conflicting constraints and checks the layout. The system continues to break constraints until it finds a valid layout.

  3. Auto Layout logs information about the conflict and the broken constraints to the console.

文档没有指定打破了哪个约束 - 它是有意的,因此您不会依赖它,而是 明确决定应该通过降低优先级来打破哪个约束


实证评估

您可以通过设置两个绝对冲突的约束来简单地测试行为:

NSLayoutConstraint.activate([
        view.heightAnchor.constraint(equalToConstant: 81),
        view.heightAnchor.constraint(equalToConstant: 60),
    ])

这会引起冲突,控制台会报错:

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:0x1c0099550 molly.QuestionInboxLinkPreView:0x10791dd40.height == 81   (active)>",
    "<NSLayoutConstraint:0x1c008c300 molly.QuestionInboxLinkPreView:0x10791dd40.height == 60   (active)>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x1c0099550 molly.QuestionInboxLinkPreView:0x10791dd40.height == 81   (active)>

奇怪的是,如果您指定两个冲突的约束,其中两个约束的优先级都低于要求的优先级 ('priority<1000'),那么冲突就会存在,行为也会模棱两可,但您不会在控制台中收到警告.对此要小心。您可以使用以下方法对其进行测试:

let constraint1 = view.heightAnchor.constraint(equalToConstant: 81)
constraint1.priority = UILayoutPriority(rawValue: 999)
let constraint2 = view.heightAnchor.constraint(equalToConstant: 60)
constraint2.priority = UILayoutPriority(rawValue: 999)
NSLayoutConstraint.activate([constraint1, constraint2])

我猜原因是由于破坏的约束不是required,系统没有足够关心来报告它。但它可能会导致一些丑陋的情况 - 请注意并小心。


你的例子

现在考虑你的例子:

NSLayoutConstraint.activate([
    aView.topAnchor.constraint(equalTo: cView.topAnchor) //#1
    aView.topAnchor.constraint(greaterThanOrEqualTo: bView.bottomAnchor, constant: 10) //#2
])

只是这两个约束不必冲突。你是说 a.top = c.top and a.top >= b.bottom', which can be satisfied if c.top >= b.bottom. So unless there are other constraints with the same priority that conflict with c.top >= b.bottom`,没有理由让自动布局识别冲突。

另外,如果没有约束.required,即使有也不会报冲突