我不知道这是一个 Swift bug 还是我犯了一个错误,但有一个奇怪的行为。
我在水平 UIStackView 中有一个 UILabel 和一个 UISwitch,但 UISwitch 的尾部被切断,因为它伸出了 stackView(参见图片)。
有人有类似的问题还是只有我一个人有类似的问题? 如果这是 Swift 的错误,有解决方法吗?
这是我的代码:
private lazy var alreadyInPlaceStackView: UIStackView = {
UIStackView(arrangedSubviews: [alreadyInPlaceLabel, alreadyInPlaceSwitch],
axis: .horizontal,
spacing: Constants.horizontalPadding,
alignment: .fill,
distribution: .fill)
}()
private lazy var alreadyInPlaceLabel: UILabel = {
let label = UILabel()
label.textColor = UIColor.conference.background.on_background
label.numberOfLines = 1
label.font = UIFont.label
label.text = "report.intubation.already-in-place.title".localized()
return label
}()
private lazy var alreadyInPlaceSwitch: UISwitch = {
let view = UISwitch()
view.onTintColor = UIColor.conference.highlight.primary
view.addTarget(self,
action: #selector(switchValueDidChange(_:)),
for: .valueChanged)
view.setContentCompressionResistancePriority(.required, for: .horizontal)
return view
}()
限制:
alreadyInPlaceStackView.leadingAnchor.constraint(equalTo: switchStackViewContainerView.leadingAnchor),
alreadyInPlaceStackView.trailingAnchor.constraint(equalTo: switchStackViewContainerView.trailingAnchor),
alreadyInPlaceStackView.topAnchor.constraint(equalTo: videoLaryngoscopeStackView.bottomAnchor, constant: Constants.verticalPadding),
alreadyInPlaceStackView.bottomAnchor.constraint(equalTo: switchStackViewContainerView.bottomAnchor),
switchStackViewContainerView.leadingAnchor.constraint(equalTo: detailsContainer.leadingAnchor),
switchStackViewContainerView.trailingAnchor.constraint(equalTo: view.trailingAnchor)
switchStackViewContainerView.topAnchor.constraint(equalTo: difficultIntubationStackView.bottomAnchor, constant: Constants.verticalPadding),
switchStackViewContainerView.bottomAnchor.constraint(equalTo: detailsContainer.bottomAnchor),
谢谢!
决定对此进行更多调查...我对“尾随”方面的看法是错误的。
让我们看一个简单的示例 - 我们将添加一个蓝色
UIView
和一个 UISwitch
,并将蓝色视图的宽度限制为开关的宽度:
class ViewController: UIViewController {
let theSwitch: UISwitch = {
let v = UISwitch()
v.backgroundColor = .green
return v
}()
let blueView: UIView = {
let v = UIView()
v.backgroundColor = .systemBlue
return v
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemBackground
[blueView, theSwitch].forEach { v in
v.translatesAutoresizingMaskIntoConstraints = false
}
view.addSubview(blueView)
view.addSubview(theSwitch)
let g = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
// blueView width and height equal to theSwitch
blueView.widthAnchor.constraint(equalTo: theSwitch.widthAnchor),
blueView.heightAnchor.constraint(equalTo: theSwitch.heightAnchor),
// blueView top and leading
blueView.topAnchor.constraint(equalTo: g.topAnchor, constant: 20.0),
blueView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
// theSwitch top to blueView bottom, leading to blueView leading
theSwitch.topAnchor.constraint(equalTo: blueView.bottomAnchor, constant: 0.0),
theSwitch.leadingAnchor.constraint(equalTo: blueView.leadingAnchor, constant: 0.0),
])
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
print("blueView width:", blueView.frame.width)
print("theSwitch width:", theSwitch.frame.width)
}
}
这是我们得到的:
并且,如果我们点击,我们会在调试控制台中看到:
blueView width: 49.0
theSwitch width: 51.0
开关比蓝色视图宽 2 点!!!
因此,让我们尝试在开关完全布局后设置蓝色视图的宽度约束。
我们注释掉宽度约束:
// don't set blueView width
//blueView.widthAnchor.constraint(equalTo: theSwitch.widthAnchor),
// blueView height equal to theSwitch
blueView.heightAnchor.constraint(equalTo: theSwitch.heightAnchor),
点击后,我们将进行设置:
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
// now we set blueView width
blueView.widthAnchor.constraint(equalTo: theSwitch.widthAnchor).isActive = true
// print widths after layout pass
DispatchQueue.main.async {
print("blueView width:", self.blueView.frame.width)
print("theSwitch width:", self.theSwitch.frame.width)
}
}
点击之前看起来像这样(因为 blueView 没有宽度):点击后:
控制台输出又是:
blueView width: 49.0
theSwitch width: 51.0
平等显然并不总是平等!!!
class ViewController: UIViewController {
let theSwitch: UISwitch = {
let v = UISwitch()
v.backgroundColor = .green
return v
}()
let blueView: UIView = {
let v = UIView()
v.backgroundColor = .systemBlue
return v
}()
let theLabel: UILabel = {
let v = UILabel()
v.text = "Option 1:"
return v
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemBackground
[blueView, theSwitch, theLabel].forEach { v in
v.translatesAutoresizingMaskIntoConstraints = false
}
// let's embed theSwitch and theLabel in blueView
blueView.addSubview(theLabel)
blueView.addSubview(theSwitch)
view.addSubview(blueView)
let g = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
// we're going to right-align the switch in the blue view
blueView.widthAnchor.constraint(equalToConstant: 128.0),
// blueView height equal to theSwitch + 16 (so we have 8-points top/bottom "padding"
blueView.heightAnchor.constraint(equalTo: theSwitch.heightAnchor, constant: 16.0),
// blueView top and leading
blueView.topAnchor.constraint(equalTo: g.topAnchor, constant: 20.0),
blueView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
// center theLabel vertically and left-align it
theLabel.centerYAnchor.constraint(equalTo: blueView.centerYAnchor),
theLabel.leadingAnchor.constraint(equalTo: blueView.leadingAnchor, constant: 0.0),
// center theSwitch vertically
theSwitch.centerYAnchor.constraint(equalTo: blueView.centerYAnchor),
// right-align theSwitch
theSwitch.trailingAnchor.constraint(equalTo: blueView.trailingAnchor, constant: 0.0),
])
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
// clear the background colors
blueView.backgroundColor = .clear
theSwitch.backgroundColor = .clear
// set clipsToBounds
blueView.clipsToBounds = true
}
}
我们得到这个:点击后我们将清除背景,并且我们将打开
clipsToBounds
以获得蓝色视图:
bug。
值得注意...如果我们评估开关的intrinsicContentSize
:
print("theSwitch.intrinsicContentSize:", theSwitch.intrinsicContentSize)
print("theSwitch.frame.size :", theSwitch.frame.size)
控制台显示:
theSwitch.intrinsicContentSize: (49.0, 31.0)
theSwitch.frame.size : (51.0, 31.0)