场景
代码
class ViewController: UIViewController {
weak var exitButton: UIButton?
weak var titleLabel: UILabel?
weak var editButton: UIButton?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
setupUI()
}
func setupUI() {
let containerView = UIView()
containerView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(containerView)
let exitButton = UIButton()
exitButton.backgroundColor = .black
exitButton.setImage(UIImage(systemName: "chevron.backward"), for: .normal)
exitButton.translatesAutoresizingMaskIntoConstraints = false
containerView.addSubview(exitButton)
let titleLabel = UILabel()
titleLabel.backgroundColor = .gray
titleLabel.text = "Title"
titleLabel.textAlignment = .center
titleLabel.translatesAutoresizingMaskIntoConstraints = false
containerView.addSubview(titleLabel)
let editButton = UIButton()
editButton.backgroundColor = .black
editButton.setTitle("Edit", for: .normal)
editButton.translatesAutoresizingMaskIntoConstraints = false
containerView.addSubview(editButton)
self.exitButton = exitButton
self.titleLabel = titleLabel
self.editButton = editButton
let safeAnchor = view.safeAreaLayoutGuide
containerView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
containerView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
containerView.topAnchor.constraint(equalTo: safeAnchor.topAnchor).isActive = true
containerView.heightAnchor.constraint(equalToConstant: 50).isActive = true
// exit button 在左边
// edit button 在右边
// title label 居中
exitButton.heightAnchor.constraint(equalToConstant: 30).isActive = true
exitButton.widthAnchor.constraint(equalToConstant: 30).isActive = true
exitButton.leadingAnchor.constraint(equalTo: containerView.leadingAnchor, constant: 10).isActive = true
exitButton.centerYAnchor.constraint(equalTo: containerView.centerYAnchor).isActive = true
editButton.contentEdgeInsets = UIEdgeInsets(top: 0, left: 10, bottom: 0, right: 10)
editButton.trailingAnchor.constraint(equalTo: containerView.trailingAnchor, constant: -10).isActive = true
editButton.centerYAnchor.constraint(equalTo: containerView.centerYAnchor).isActive = true
titleLabel.centerXAnchor.constraint(equalTo: containerView.centerXAnchor).isActive = true
titleLabel.centerYAnchor.constraint(equalTo: containerView.centerYAnchor).isActive = true
}
}
现在需要扩大 title label 的响应热区,把 title label 拉伸,填充中间的区域,增加下面的代码
titleLabel.leadingAnchor.constraint(equalTo: exitButton.trailingAnchor).isActive = true
titleLabel.trailingAnchor.constraint(equalTo: editButton.leadingAnchor).isActive = true
增加代码后,edit button 被压缩了
尝试的方法
添加约束,设置 edit button 的宽度为其固有大小
editButton.setContentHuggingPriority(.required, for: .horizontal)
editButton.setContentCompressionResistancePriority(.required, for: .horizontal)
没效果。
我思考的原因是:
约束
titleLabel.centerXAnchor.constraint(equalTo: containerView.centerXAnchor).isActive = true
和
titleLabel.leadingAnchor.constraint(equalTo: exitButton.trailingAnchor).isActive = true
titleLabel.trailingAnchor.constraint(equalTo: editButton.leadingAnchor).isActive = true
组合在一起有问题。
设置了 title label 居中后,title label 就是以 centerXAnchor 为轴的轴对称图形了。再设置 exit button 和 edit button 相邻,因为 exit button 的宽度小于 edit button 的宽度,(centerX - exitButton.trailing) > (editButton.leading - centerX),自动布局为了保证 titleLabel.leadingAnchor.constraint(equalTo: exitButton.trailingAnchor)
在右边拉伸了 title label,压缩了 edit button,使得 (centerX - exitButton.trailing) = (editButton.leading - centerX)。
考虑 (centerX - exitButton.trailing) > (editButton.leading - centerX),把 title label 的约束改为
// editButton.setContentHuggingPriority(.required, for: .horizontal)
// editButton.setContentCompressionResistancePriority(.required, for: .horizontal)
titleLabel.centerXAnchor.constraint(equalTo: containerView.centerXAnchor).isActive = true
titleLabel.centerYAnchor.constraint(equalTo: containerView.centerYAnchor).isActive = true
titleLabel.leadingAnchor.constraint(greaterThanOrEqualTo: exitButton.trailingAnchor).isActive = true
titleLabel.trailingAnchor.constraint(equalTo: editButton.leadingAnchor).isActive = true
效果
重新设置 edit button 的宽度为其固有大小
editButton.setContentHuggingPriority(.required, for: .horizontal)
editButton.setContentCompressionResistancePriority(.required, for: .horizontal)
titleLabel.centerXAnchor.constraint(equalTo: containerView.centerXAnchor).isActive = true
titleLabel.centerYAnchor.constraint(equalTo: containerView.centerYAnchor).isActive = true
titleLabel.leadingAnchor.constraint(greaterThanOrEqualTo: exitButton.trailingAnchor).isActive = true
titleLabel.trailingAnchor.constraint(equalTo: editButton.leadingAnchor).isActive = true
效果
现在实现了我的目的——扩大 title label 的响应热区。
这时又有一个问题了,如果 exit button 的宽度大于 edit button 的宽度,怎么办?重新改代码?有没有更好的设置约束的方法?
改变 title label 和 edit button 之间间距的约束是不行的
editButton.setContentHuggingPriority(.required, for: .horizontal)
editButton.setContentCompressionResistancePriority(.required, for: .horizontal)
titleLabel.centerXAnchor.constraint(equalTo: containerView.centerXAnchor).isActive = true
titleLabel.centerYAnchor.constraint(equalTo: containerView.centerYAnchor).isActive = true
titleLabel.leadingAnchor.constraint(greaterThanOrEqualTo: exitButton.trailingAnchor).isActive = true
titleLabel.trailingAnchor.constraint(lessThanOrEqualTo: editButton.leadingAnchor).isActive = true
解决方法
改变 title label 和 edit button 之间间距的约束的优先级,优先级要设置成比正常的 1000 低。我发现优先级设置成 UILayoutPriority.defaultHigh
有效果。
editButton.setContentHuggingPriority(.required, for: .horizontal)
editButton.setContentCompressionResistancePriority(.required, for: .horizontal)
titleLabel.centerXAnchor.constraint(equalTo: containerView.centerXAnchor).isActive = true
titleLabel.centerYAnchor.constraint(equalTo: containerView.centerYAnchor).isActive = true
let leftConstraint = titleLabel.leadingAnchor.constraint(equalTo: exitButton.trailingAnchor)
leftConstraint.priority = UILayoutPriority.defaultHigh
leftConstraint.isActive = true
let rightConstraint = titleLabel.trailingAnchor.constraint(equalTo: editButton.leadingAnchor)
rightConstraint.priority = UILayoutPriority.defaultHigh
rightConstraint.isActive = true
提高 exit button 的宽度,重新运行
好了,(完美)解决问题。