自动布局在显示1个标签的情况下不起作用,但可以使用2个标签

时间:2019-07-04 23:44:20

标签: ios swift ios-autolayout

当标签是容器视图层次结构中的唯一标签时,标签将在其容器外部扩展。如果有两个标签,则可以正常工作,并且两个标签都位于容器视图内。

我的实际用例更加复杂,但是我尝试将其简化为下面的代码。

Xcode 10.2游乐场代码(Swift 5):

import UIKit
import Foundation
import PlaygroundSupport

let viewController = UIViewController()
viewController.view.backgroundColor = UIColor.green

let containerView = UIView()
containerView.backgroundColor = .gray
containerView.translatesAutoresizingMaskIntoConstraints = false
viewController.view.addSubview(containerView)

containerView.widthAnchor.constraint(equalToConstant: 200).isActive = true
containerView.heightAnchor.constraint(equalToConstant: 200).isActive = true
containerView.centerXAnchor.constraint(equalTo: viewController.view.centerXAnchor).isActive = true
containerView.centerYAnchor.constraint(equalTo: viewController.view.centerYAnchor).isActive = true

let topologyView = UIView()
topologyView.backgroundColor = .blue
topologyView.translatesAutoresizingMaskIntoConstraints = false
containerView.addSubview(topologyView)

let leadingConstraint = topologyView.leadingAnchor.constraint(greaterThanOrEqualTo: containerView.leadingAnchor)
print(leadingConstraint.priority)
leadingConstraint.priority = .defaultLow
leadingConstraint.isActive = true

let trailingConstraint = topologyView.trailingAnchor.constraint(greaterThanOrEqualTo: containerView.trailingAnchor)
trailingConstraint.priority = .defaultLow
trailingConstraint.isActive = true

let topConstraint = topologyView.topAnchor.constraint(greaterThanOrEqualTo: containerView.topAnchor)
topConstraint.priority = .defaultLow
topConstraint.isActive = true

let bottomConstraint = topologyView.bottomAnchor.constraint(greaterThanOrEqualTo: containerView.bottomAnchor)
bottomConstraint.priority = .defaultLow
bottomConstraint.isActive = true

topologyView.centerXAnchor.constraint(equalTo: containerView.centerXAnchor).isActive = true
topologyView.centerYAnchor.constraint(equalTo: containerView.centerYAnchor).isActive = true

let label1Title = "1234"
let label1 = UILabel()
label1.translatesAutoresizingMaskIntoConstraints = false
label1.text = Array(repeating: label1Title, count: 10).joined()
label1.setContentHuggingPriority(.required, for: .horizontal)
label1.setContentCompressionResistancePriority(.required, for: .horizontal)
topologyView.addSubview(label1)

label1.leadingAnchor.constraint(equalTo: topologyView.leadingAnchor).isActive = true
label1.trailingAnchor.constraint(equalTo: topologyView.trailingAnchor).isActive = true
label1.bottomAnchor.constraint(equalTo: topologyView.bottomAnchor).isActive = true
label1.topAnchor.constraint(equalTo: topologyView.topAnchor).isActive = true

let window = UIWindow(frame: CGRect(x: 0, y: 0, width: 300, height: 350))
window.rootViewController = viewController

PlaygroundPage.current.liveView = window
PlaygroundPage.current.needsIndefiniteExecution = true

window.makeKeyAndVisible()

print(topologyView.contentHuggingPriority(for: .horizontal))
print(topologyView.contentCompressionResistancePriority(for: .horizontal))

print(containerView.contentHuggingPriority(for: .horizontal))
print(containerView.contentCompressionResistancePriority(for: .horizontal))


结果如下图所示: a busy cat

如果我尝试使用2个标签,它将产生正确的结果,以使标签不会扩展容器的宽度:

import UIKit
import Foundation
import PlaygroundSupport

let viewController = UIViewController()
viewController.view.backgroundColor = UIColor.green

let containerView = UIView()
containerView.backgroundColor = .gray
containerView.translatesAutoresizingMaskIntoConstraints = false
viewController.view.addSubview(containerView)

containerView.widthAnchor.constraint(equalToConstant: 200).isActive = true
containerView.heightAnchor.constraint(equalToConstant: 200).isActive = true
containerView.centerXAnchor.constraint(equalTo: viewController.view.centerXAnchor).isActive = true
containerView.centerYAnchor.constraint(equalTo: viewController.view.centerYAnchor).isActive = true

let topologyView = UIView()
topologyView.backgroundColor = .blue
topologyView.translatesAutoresizingMaskIntoConstraints = false
containerView.addSubview(topologyView)

let leadingConstraint = topologyView.leadingAnchor.constraint(greaterThanOrEqualTo: containerView.leadingAnchor)
print(leadingConstraint.priority)
leadingConstraint.priority = .defaultLow
leadingConstraint.isActive = true

let trailingConstraint = topologyView.trailingAnchor.constraint(greaterThanOrEqualTo: containerView.trailingAnchor)
trailingConstraint.priority = .defaultLow
trailingConstraint.isActive = true

let topConstraint = topologyView.topAnchor.constraint(greaterThanOrEqualTo: containerView.topAnchor)
topConstraint.priority = .defaultLow
topConstraint.isActive = true

let bottomConstraint = topologyView.bottomAnchor.constraint(greaterThanOrEqualTo: containerView.bottomAnchor)
bottomConstraint.priority = .defaultLow
bottomConstraint.isActive = true

topologyView.centerXAnchor.constraint(equalTo: containerView.centerXAnchor).isActive = true
topologyView.centerYAnchor.constraint(equalTo: containerView.centerYAnchor).isActive = true

let label1Title = "1234"
let label1 = UILabel()
label1.translatesAutoresizingMaskIntoConstraints = false
label1.text = Array(repeating: label1Title, count: 10).joined()
label1.setContentHuggingPriority(.required, for: .horizontal)
label1.setContentCompressionResistancePriority(.required, for: .horizontal)
topologyView.addSubview(label1)

label1.leadingAnchor.constraint(equalTo: topologyView.leadingAnchor).isActive = true
label1.trailingAnchor.constraint(equalTo: topologyView.trailingAnchor).isActive = true
label1.topAnchor.constraint(equalTo: topologyView.topAnchor).isActive = true

let label2 = UILabel()
label2.translatesAutoresizingMaskIntoConstraints = false
label2.text = "123124128"
label2.setContentHuggingPriority(.required, for: .horizontal)
label2.setContentCompressionResistancePriority(.required, for: .horizontal)
topologyView.addSubview(label2)

label2.leadingAnchor.constraint(equalTo: topologyView.leadingAnchor).isActive = true
label2.trailingAnchor.constraint(equalTo: topologyView.trailingAnchor).isActive = true
label2.bottomAnchor.constraint(equalTo: topologyView.bottomAnchor).isActive = true
label2.topAnchor.constraint(equalTo: label1.bottomAnchor).isActive = true

let window = UIWindow(frame: CGRect(x: 0, y: 0, width: 300, height: 350))
window.rootViewController = viewController

PlaygroundPage.current.liveView = window
PlaygroundPage.current.needsIndefiniteExecution = true

window.makeKeyAndVisible()

print(topologyView.contentHuggingPriority(for: .horizontal))
print(topologyView.contentCompressionResistancePriority(for: .horizontal))

print(containerView.contentHuggingPriority(for: .horizontal))
print(containerView.contentCompressionResistancePriority(for: .horizontal))

结果如下图所示: a busy cat

我希望当我只显示1个标签时,标签不会在其容器外扩展。

我想知道为什么前导约束和尾随约束在第一种情况下(带有1个标签)不能正常工作,而在第二种情况下(具有2个标签)可以正常工作吗?

2 个答案:

答案 0 :(得分:1)

您有几处错误。

如果将label2的文本更改为:

,请按原样使用“两个标签”的游乐场页面
label2.text = "01234567890 ABCDEFGHIJ"

您将获得:

enter image description here

如您所见,拥有两个标签并不能“解决问题”……它看起来似乎是因为您为第二个标签使用了非常短的字符串。

发生的事情是:当自动布局处理约束并发现不能完全满足所有约束时,它将使用优先级来确定可以打破哪些约束而不会引发错误。在您的情况下,您正在设置各种错误约束和优先级,这些约束和优先级赋予了自动布局更改布局的权限。

因此,首先,我不知道您是怎么想将topologyView的前,后,顶部和底部约束的优先级设置为.defaultLow的。这样做是 明确 ,告诉自动布局在需要时忽略这些约束。然后,您添加一个比topologyView宽的标签,并按照您的指示进行自动布局并打破约束。

在您的“两个标签”示例中,自动布局将label2放在优先位置–只是发生使它看起来正确(直到您将标签变宽)。 / p>

接下来,您使用的greaterThanOrEqualTo错误。通过设置:

topologyView.trailingAnchor.constraint(greaterThanOrEqualTo: containerView.trailingAnchor)

您说的是“让topologyView的后沿超出 containerView的后沿。您真正想要的是 小于

topologyView.trailingAnchor.constraint(lessThanOrEqualTo: containerView.trailingAnchor)

这将使topologyView的后沿 小于containerView的后沿。

现在,不清楚是否要使标签适合containerView的整个宽度,还是要使标签都短一点,请使其居中。

如果是全宽,请使用equalTo ...,如果居中,请使用greatThanOrEqualTo开头,并使用lessThanOrEqualTo结尾。

这同样适用于底部约束。

所以...您的“单个标签”示例变为:

import UIKit
import Foundation
import PlaygroundSupport

let viewController = UIViewController()
viewController.view.backgroundColor = UIColor.green

let containerView = UIView()
containerView.backgroundColor = .gray
containerView.translatesAutoresizingMaskIntoConstraints = false
viewController.view.addSubview(containerView)

containerView.widthAnchor.constraint(equalToConstant: 200).isActive = true
containerView.heightAnchor.constraint(equalToConstant: 200).isActive = true
containerView.centerXAnchor.constraint(equalTo: viewController.view.centerXAnchor).isActive = true
containerView.centerYAnchor.constraint(equalTo: viewController.view.centerYAnchor).isActive = true

let topologyView = UIView()
topologyView.backgroundColor = .blue
topologyView.translatesAutoresizingMaskIntoConstraints = false
containerView.addSubview(topologyView)

let leadingConstraint = topologyView.leadingAnchor.constraint(greaterThanOrEqualTo: containerView.leadingAnchor)
// use default priority
//leadingConstraint.priority = .defaultLow
leadingConstraint.isActive = true

// use lessThanOrEqualTo
let trailingConstraint = topologyView.trailingAnchor.constraint(lessThanOrEqualTo: containerView.trailingAnchor)
// use default priority
//trailingConstraint.priority = .defaultLow
trailingConstraint.isActive = true

let topConstraint = topologyView.topAnchor.constraint(greaterThanOrEqualTo: containerView.topAnchor)
// use default priority
//topConstraint.priority = .defaultLow
topConstraint.isActive = true

// use lessThanOrEqualTo
let bottomConstraint = topologyView.bottomAnchor.constraint(lessThanOrEqualTo: containerView.bottomAnchor)
// use default priority
//bottomConstraint.priority = .defaultLow
bottomConstraint.isActive = true

topologyView.centerXAnchor.constraint(equalTo: containerView.centerXAnchor).isActive = true
topologyView.centerYAnchor.constraint(equalTo: containerView.centerYAnchor).isActive = true

let label1Title = "1234"
let label1 = UILabel()
label1.backgroundColor = .yellow
label1.translatesAutoresizingMaskIntoConstraints = false
label1.text = Array(repeating: label1Title, count: 10).joined()
// we can leave Hugging and Compression at default Priority
//label1.setContentHuggingPriority(.required, for: .horizontal)
//label1.setContentCompressionResistancePriority(.required, for: .horizontal)
topologyView.addSubview(label1)

label1.leadingAnchor.constraint(equalTo: topologyView.leadingAnchor).isActive = true
label1.trailingAnchor.constraint(equalTo: topologyView.trailingAnchor).isActive = true
label1.bottomAnchor.constraint(equalTo: topologyView.bottomAnchor).isActive = true
label1.topAnchor.constraint(equalTo: topologyView.topAnchor).isActive = true

let window = UIWindow(frame: CGRect(x: 0, y: 0, width: 300, height: 350))
window.rootViewController = viewController

PlaygroundPage.current.liveView = window
PlaygroundPage.current.needsIndefiniteExecution = true

window.makeKeyAndVisible()

产生(简短标签):

enter image description here

或(长标签):

enter image description here

您的“两个标签”示例为:

import UIKit
import Foundation
import PlaygroundSupport

let viewController = UIViewController()
viewController.view.backgroundColor = UIColor.green

let containerView = UIView()
containerView.backgroundColor = .gray
containerView.translatesAutoresizingMaskIntoConstraints = false
viewController.view.addSubview(containerView)

containerView.widthAnchor.constraint(equalToConstant: 200).isActive = true
containerView.heightAnchor.constraint(equalToConstant: 200).isActive = true
containerView.centerXAnchor.constraint(equalTo: viewController.view.centerXAnchor).isActive = true
containerView.centerYAnchor.constraint(equalTo: viewController.view.centerYAnchor).isActive = true

let topologyView = UIView()
topologyView.backgroundColor = .blue
topologyView.translatesAutoresizingMaskIntoConstraints = false
containerView.addSubview(topologyView)

let leadingConstraint = topologyView.leadingAnchor.constraint(greaterThanOrEqualTo: containerView.leadingAnchor)
// use default priority
//leadingConstraint.priority = .defaultLow
leadingConstraint.isActive = true

// use lessThanOrEqualTo
let trailingConstraint = topologyView.trailingAnchor.constraint(lessThanOrEqualTo: containerView.trailingAnchor)
// use default priority
//trailingConstraint.priority = .defaultLow
trailingConstraint.isActive = true

let topConstraint = topologyView.topAnchor.constraint(greaterThanOrEqualTo: containerView.topAnchor)
// use default priority
//topConstraint.priority = .defaultLow
topConstraint.isActive = true

// use lessThanOrEqualTo
let bottomConstraint = topologyView.bottomAnchor.constraint(lessThanOrEqualTo: containerView.bottomAnchor)
// use default priority
//bottomConstraint.priority = .defaultLow
bottomConstraint.isActive = true

topologyView.centerXAnchor.constraint(equalTo: containerView.centerXAnchor).isActive = true
topologyView.centerYAnchor.constraint(equalTo: containerView.centerYAnchor).isActive = true

let label1Title = "1234"
let label1 = UILabel()
label1.backgroundColor = .yellow
label1.translatesAutoresizingMaskIntoConstraints = false
label1.text = Array(repeating: label1Title, count: 10).joined()
// we can leave Hugging and Compression at default Priority
//label1.setContentHuggingPriority(.required, for: .horizontal)
//label1.setContentCompressionResistancePriority(.required, for: .horizontal)
topologyView.addSubview(label1)

label1.leadingAnchor.constraint(equalTo: topologyView.leadingAnchor).isActive = true
label1.trailingAnchor.constraint(equalTo: topologyView.trailingAnchor).isActive = true
label1.topAnchor.constraint(equalTo: topologyView.topAnchor).isActive = true

let label2 = UILabel()
label2.backgroundColor = .orange
label2.translatesAutoresizingMaskIntoConstraints = false
label2.text = "012345 ABCDE"
// we can leave Hugging and Compression at default Priority
//label2.setContentHuggingPriority(.required, for: .horizontal)
//label2.setContentCompressionResistancePriority(.required, for: .horizontal)
topologyView.addSubview(label2)

label2.leadingAnchor.constraint(equalTo: topologyView.leadingAnchor).isActive = true
label2.trailingAnchor.constraint(equalTo: topologyView.trailingAnchor).isActive = true
label2.bottomAnchor.constraint(equalTo: topologyView.bottomAnchor).isActive = true
label2.topAnchor.constraint(equalTo: label1.bottomAnchor).isActive = true

let window = UIWindow(frame: CGRect(x: 0, y: 0, width: 300, height: 350))
window.rootViewController = viewController

PlaygroundPage.current.liveView = window
PlaygroundPage.current.needsIndefiniteExecution = true

window.makeKeyAndVisible()

带有短标签和长标签的结果:

enter image description here

enter image description here

答案 1 :(得分:0)

我发现您设置了label1.setContentHuggingPriority(.required, for: .horizontal)。请尝试将优先级降低为high,而不是require