This is an auto-layout related question. I've containerView
which has two subviews: imageView
and label
. I want to let the fontsize of the label
determine the size of the containerView
according to the aspect ratio of imageView
.
When the font size increases, the containerView
and the imageView
should get bigger maintaining the aspect ratio and keeping the label
centered with some padding as shown in the image below.
And I want to achieve it programmatically.
Any help will be much appreciated
You can accomplish this by:
Here's an example, including buttons to increase / decrease the font size:
class WalterViewController: UIViewController {
let theContainerView: UIView = {
let v = UIView()
v.backgroundColor = .blue
return v
}()
let theImageView: UIImageView = {
let v = UIImageView()
v.backgroundColor = .red
v.contentMode = .scaleToFill
return v
}()
let theLabel: UILabel = {
let v = UILabel()
v.backgroundColor = .yellow
v.textAlignment = .center
v.text = "TEST"
// content vertical hugging REQUIRED !!!
v.setContentHuggingPriority(.required, for: .vertical)
return v
}()
let btnUp: UIButton = {
let b = UIButton(type: .system)
b.backgroundColor = UIColor(white: 0.9, alpha: 1.0)
b.setTitle("Increase", for: .normal)
return b
}()
let btnDn: UIButton = {
let b = UIButton(type: .system)
b.backgroundColor = UIColor(white: 0.9, alpha: 1.0)
b.setTitle("Decrease", for: .normal)
return b
}()
let btnStack: UIStackView = {
let v = UIStackView()
v.axis = .horizontal
v.spacing = 12
v.distribution = .fillEqually
return v
}()
override func viewDidLoad() {
super.viewDidLoad()
// we'll be using constraints
[theContainerView, theImageView, theLabel, btnUp, btnDn, btnStack].forEach {
$0.translatesAutoresizingMaskIntoConstraints = false
}
// add buttons to the stack
btnStack.addArrangedSubview(btnUp)
btnStack.addArrangedSubview(btnDn)
// add imageView and label to container
theContainerView.addSubview(theImageView)
theContainerView.addSubview(theLabel)
// add button stack and container view to view
view.addSubview(btnStack)
view.addSubview(theContainerView)
// respect safe area
let g = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
// horizontal button stack 20-points from top, 40-points on each side
btnStack.topAnchor.constraint(equalTo: g.topAnchor, constant: 20.0),
btnStack.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 40.0),
btnStack.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -40.0),
// container view centered in view safeArea
theContainerView.centerXAnchor.constraint(equalTo: g.centerXAnchor),
theContainerView.centerYAnchor.constraint(equalTo: g.centerYAnchor),
// constrain image view to its superView (container view)
// 8-pts on all 4 sides
theImageView.topAnchor.constraint(equalTo: theContainerView.topAnchor, constant: 8.0),
theImageView.leadingAnchor.constraint(equalTo: theContainerView.leadingAnchor, constant: 8.0),
theImageView.trailingAnchor.constraint(equalTo: theContainerView.trailingAnchor, constant: -8.0),
theImageView.bottomAnchor.constraint(equalTo: theContainerView.bottomAnchor, constant: -8.0),
// label is centered in its superView (container view)
theLabel.centerXAnchor.constraint(equalTo: theContainerView.centerXAnchor),
theLabel.centerYAnchor.constraint(equalTo: theContainerView.centerYAnchor),
// constrain imageView to 16:9 ratio
theImageView.widthAnchor.constraint(equalTo: theImageView.heightAnchor, multiplier: 16.0 / 9.0),
// constrain imageView's height to label's height +40
// will result in 20-pts on top and bottom
theImageView.heightAnchor.constraint(equalTo: theLabel.heightAnchor, constant: 40.0),
])
// load an image
if let img = UIImage(named: "bkg640x360") {
theImageView.image = img
}
// add targets to buttons to increase / decrease the label's font size
btnUp.addTarget(self, action: #selector(increaseTapped(_:)), for: .touchUpInside)
btnDn.addTarget(self, action: #selector(decreaseTapped(_:)), for: .touchUpInside)
}
@objc func increaseTapped(_ sender: Any?) -> Void {
theLabel.font = theLabel.font.withSize(theLabel.font.pointSize + 1.0)
}
@objc func decreaseTapped(_ sender: Any?) -> Void {
theLabel.font = theLabel.font.withSize(theLabel.font.pointSize - 1.0)
}
}
How it looks on launch (container view is centered in root view):
and, after tapping Increase a bunch of times: