I am trying to use Autolayout (programmatically) to produce the following scene. As the picture indicates, the button's height cannot be greater then 56 and less than 44 in any screen size. The top content view, has its own size based on its internal contents, but its top anchor has to have a minimum toppadding of 8. It can be greater than 8. The padding between the buttons and the content view is strict 8pts. and the bottom padding with the bottom anchor is a strict 12. The only thing that I can play with is the button's height to adjust all the contents in a small screen.
Tries 1) I tried putting all the buttons in a stack view, and have put both the height constraint to each of the buttons.
button.heightAnchor.constraint(lessThanOrEqualToConstant: 56).isActive = true
button.heightAnchor.constraint(greaterThanOrEqualToConstant: 44).isActive = true
but the button height never increases more than 44. Now, it works correctly, when I set the top constraint between main view and top view with a strict 8
contentView.topAnchor.constraint(equalTo: topAnchor, constant: 8).isActive = true
and not a
contentView.topAnchor.constraint(greaterThanOrEqualTo: topAnchor, constant: 8).isActive = true
But that won't work with larger screens as the top view needs to be closer to the buttons then the top view.
2) When I don't use the stack view, and set both the height constraint to each button, no matter which ever device it is, it never increases more than 44. If I remove the greaterthen 44 constraint, then the size of the button reduces to 36. I tried setting priority to topmost greaterthen 8 constraint as well as height of the button constraints, as well as setting aspect ratio constraint between the content view and the top button, and then setting all the other button height to the top button, but then again, all just sticks up to 44.
Please advise or provide any solution how to tackle this.
This is really fairly straight-forward if you "talk it out" to yourself.
The easy parts:
8-pts
Leading and Trailing 16-pts
from the Bottom>= 8-pts
from the top >= 44
<= 56
The "tricky" parts:
= 8-pts
with .priority =.defaultHigh
Here is a full example (all code, no Storyboard connections). The "top" view will start at 240-pts tall... each time you tap the first button the top view's height will increase by 20, to a max of 400. The top view will also display the new heights:
class TestViewController: UIViewController {
let stackView: UIStackView = {
let v = UIStackView()
v.translatesAutoresizingMaskIntoConstraints = false
v.axis = .vertical
v.spacing = 8
return v
}()
let dynaView: UILabel = {
let v = UILabel()
v.translatesAutoresizingMaskIntoConstraints = false
v.backgroundColor = .yellow
v.textAlignment = .center
v.numberOfLines = 0
return v
}()
var dynaViewHeightConstraint: NSLayoutConstraint!
var theButtons: [UIButton] = [UIButton]()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(stackView)
let g = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
// stackView constrained 8-pts Leading and Trailing
// 16-pts from bottom
// >= 8-pts from top
stackView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 8.0),
stackView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -8.0),
stackView.bottomAnchor.constraint(equalTo: g.bottomAnchor, constant: -16.0),
stackView.topAnchor.constraint(greaterThanOrEqualTo: g.topAnchor, constant: 8.0),
])
// we need a stackView TOP anchor = 8 with priorty 750
// this will "pull" the top up as far as it can, without violating the
// button height constraints
let stackTop = stackView.topAnchor.constraint(equalTo: g.topAnchor, constant: 8.0)
stackTop.priority = .defaultHigh
stackTop.isActive = true
for i in 1...4 {
let b = UIButton()
b.translatesAutoresizingMaskIntoConstraints = false
b.setTitle("Button \(i)", for: [])
b.backgroundColor = .red
NSLayoutConstraint.activate([
// button heights are min: 44 max: 56
b.heightAnchor.constraint(lessThanOrEqualToConstant: 56.0),
b.heightAnchor.constraint(greaterThanOrEqualToConstant: 44.0),
])
theButtons.append(b)
}
// let's start with the dynaView height at 240
dynaViewHeightConstraint = dynaView.heightAnchor.constraint(equalToConstant: 240.0)
dynaViewHeightConstraint.isActive = true
// add dynsView to the stack
stackView.addArrangedSubview(dynaView)
guard let firstButton = theButtons.first else {
fatalError("Something is wrong with my setup!")
}
// add each button to the stack,
// setting its height equal to the first button's height
theButtons.forEach { b in
stackView.addArrangedSubview(b)
if b != theButtons.first {
b.heightAnchor.constraint(equalTo: firstButton.heightAnchor).isActive = true
}
}
// tapping the first button will increae dynaView's height
firstButton.addTarget(self, action: #selector(self.didTap(_:)), for: .touchUpInside)
}
override func viewDidAppear(_ animated: Bool) {
showStats()
}
func showStats() -> Void {
var s = "DynaView Height: \(dynaView.frame.height)"
for i in 0..<theButtons.count {
let b = theButtons[i]
s += "\n"
s += "Button \(i + 1) Height: \(b.frame.height)"
}
dynaView.text = s
}
@objc
func didTap(_ sender: Any) -> Void {
let h = min(dynaViewHeightConstraint.constant + 20, 400)
dynaViewHeightConstraint.constant = h
DispatchQueue.main.async {
self.showStats()
}
}
}
Here's how it looks on an iPhone 8...
and on an iPhone 11 with top-view height at 400 max:
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.