This is the layout. The top Label text may get very long, and I expect the Label selected at the bottom to be at least 40 pt from the bottom button when there is enough space at the moment, and at least 10 pt when there is not enough space.I tried prioritizing but it doesn't seem to work, please help me. Here is part of my code.
buttonView.snp.updateConstraints { (make) in
make.leading.bottom.trailing.equalToSuperview()
make.height.equalTo(buttonView.intrinsicContentSize.height)
}
contentLabel.snp.updateConstraints { (make) in
make.top.greaterThanOrEqualTo(headerImageView.snp.bottom).offset(10.dp)
make.leading.equalTo(50.dph)
make.trailing.equalTo(-50.dph)
}
codeTextField.snp.updateConstraints { (make) in
make.top.equalTo(contentLabel.snp.bottom).offset(10.dp)
make.leading.equalTo(46.5.dp)
make.trailing.equalTo(-46.5.dp)
make.height.equalTo(50.dp)
}
tipsLabel.snp.updateConstraints { (make) in
make.top.equalTo(codeTextField.snp.bottom).offset(10.dp)
make.width.centerX.equalTo(codeTextField)
make.bottom.equalTo(buttonView.snp.top).offset(-10.dp)
make.bottom.greaterThanOrEqualTo(buttonView.snp.top).offset(-40.dp)
}
Click here to download the demo project.
Couple things...
First, you want to set Compression Resistance on your "tips" label so it doesn't get squeezed out of existence.
Second, when you give an object constraints such as:
bottom of viewA greaterThanOrEqual to -40 from top of viewB
bottom of viewA lessThanOrEqual to -10 from top of viewB
you have not given a complete layout. ANY value between -40 and -10 would be valid, so auto-layout doesn't understand what you really want.
To fix that, based on your descriptions, you want 40-pts if possible, and at least 10-pts. So you want two constraints that say:
at least
-10 from top of viewBequalTo
-40 from top of viewB - unless there is not enough space - so give it a Priority
less than required
Try this code - I added // MARK: DonMag ...
comments where I made changes:
class MyView: UIView {
override class var requiresConstraintBasedLayout: Bool { return true }
// MARK: DonMag - a few varied length contentLabel strings
private var idx: Int = 0
private let examples: [String] = [
"Check your email.",
"Please check your email to activate your account.\n\nEnter the activation code:",
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.",
]
private let headerView = UIButton().then {
$0.backgroundColor = .purple
$0.setTitle("Tap me!", for: .normal)
}
private let contentLabel = UILabel().then {
$0.font = .systemFont(ofSize: 21)
$0.numberOfLines = 0
$0.setContentHuggingPriority(.required, for: .vertical)
// MARK: DonMag - so we can see its frame
$0.textAlignment = .center
$0.backgroundColor = .cyan
}
private let codeTextField = UITextField().then {
$0.placeholder = "Enter code"
$0.backgroundColor = UIColor.white.withAlphaComponent(0.2)
$0.layer.cornerRadius = 8
$0.layer.borderWidth = 1
$0.layer.borderColor = UIColor.lightGray.cgColor
$0.textAlignment = .center
$0.font = .systemFont(ofSize: 21)
$0.keyboardType = .numberPad
}
private let tipsLabel = UILabel().then {
$0.font = .systemFont(ofSize: 12)
$0.adjustsFontSizeToFitWidth = true
$0.minimumScaleFactor = 0.2
$0.textAlignment = .center
$0.text = "If you have not received the code, tap 'resend'."
$0.setContentHuggingPriority(.required, for: .vertical)
// MARK: DonMag - prevent label from being compressed vertically
$0.setContentCompressionResistancePriority(.required, for: .vertical)
// MARK: DonMag - so we can see its frame
$0.backgroundColor = .yellow
}
private let bottomView = UIView().then {
$0.backgroundColor = .red
}
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = .white
addSubview(headerView)
addSubview(contentLabel)
addSubview(codeTextField)
addSubview(tipsLabel)
addSubview(bottomView)
headerView.addTarget(self, action: #selector(headerViewDidTapped), for: .touchUpInside)
headerViewDidTapped()
}
override func updateConstraints() {
headerView.snp.updateConstraints { (make) in
make.leading.trailing.top.equalToSuperview()
make.height.equalToSuperview().multipliedBy(0.454)
}
bottomView.snp.updateConstraints { (make) in
make.leading.bottom.trailing.equalToSuperview()
make.height.equalTo(121)
}
contentLabel.snp.updateConstraints { (make) in
make.top.greaterThanOrEqualTo(headerView.snp.bottom).offset(10)
make.leading.equalTo(50)
make.trailing.equalTo(-50)
}
codeTextField.snp.updateConstraints { (make) in
make.top.equalTo(contentLabel.snp.bottom).offset(10)
make.leading.equalTo(46.5)
make.trailing.equalTo(-46.5)
make.height.equalTo(50)
}
tipsLabel.snp.updateConstraints { (make) in
make.top.equalTo(codeTextField.snp.bottom).offset(10)
make.width.centerX.equalTo(codeTextField)
make.bottom.greaterThanOrEqualTo(bottomView.snp.top).offset(-40)
// MARK: DonMag - tipsLabel bottom should be equalTo -40 with medium priority (so it can be overridden by auto-layout when needed)
//make.bottom.greaterThanOrEqualTo(bottomView.snp.top).offset(-40)
make.bottom.equalTo(bottomView.snp.top).offset(-40).priority(.medium)
make.bottom.lessThanOrEqualTo(bottomView.snp.top).offset(-10)
}
super.updateConstraints()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
@objc
private func headerViewDidTapped() {
// MARK: DonMag - get example string for contentLabel
let text = examples[idx % examples.count]
idx += 1
contentLabel.text = text
setNeedsUpdateConstraints()
UIView.animate(withDuration: 0.1) {
self.layoutIfNeeded()
}
}
}