Reputation: 1212
I have a UIView that I'm appending into a stack view on my main page of my app
This is the class of my view:
class MyCustomView: UIView {
public let leftLabel: UILabel = UILabel(frame: .zero)
public let rightLabel: UILabel = UILabel(frame: .zero)
override init(frame: CGRect) {
super.init(frame: frame)
addSubview(leftLabel)
addSubview(rightLabel)
leftLabel.translatesAutoresizingMaskIntoConstraints = false
rightLabel.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
leftLabel.widthAnchor.constraint(equalTo: widthAnchor, multiplier: 0.4),
leftLabel.leadingAnchor.constraint(equalTo: leadingAnchor),
leftLabel.topAnchor.constraint(equalTo: topAnchor),
leftLabel.bottomAnchor.constraint(equalTo: bottomAnchor),
rightLabel.widthAnchor.constraint(equalTo: widthAnchor, multiplier: 0.6),
rightLabel.trailingAnchor.constraint(equalTo: trailingAnchor),
rightLabel.topAnchor.constraint(equalTo: topAnchor),
rightLabel.bottomAnchor.constraint(equalTo: bottomAnchor),
])
leftLabel.text = "Short string"
rightLabel.text = "Short string too"
}
}
And I append to my main stack view with:
let myCustomView = MyCustomView(frame: .zero)
stackView.addArrangedSubview(myCustomView)
This loads in my label's correctly and resizes everything as I'd want.
However, in my main class, I am updating myCustomView.rightLabel.text = <New Way Longer Text That Takes 2 Lines Instead of One>
The text is updating properly, but my myCustomView
size is not resizing, so part of the text is just being cut-off
I have tried following other answers on here, but none of them seem to work for me.
Am I missing something small in order to force the resize of the customView to fit the label inside of it?
Thank you in advance
Upvotes: 0
Views: 1420
Reputation: 77690
Your code does not show that you set the .numberOfLines
in the label(s) to 0
to allow for multi-line labels.
Adding only that, should allow your labels to grow in height and to expand your custom view. However... that will also make both labels expand to the size of the tallest label, resulting in the text of the "shorter" label being vertically centered (I added background colors to make it easy to see the frames / bounds of the views):
If you constrain the Bottom of your custom view to the Bottom of each label at greaterThanOrEqualTo
you can keep the labels "top-aligned":
You can run this code directly in a Playground page to see the results:
//: A UIKit based Playground for presenting user interface
import UIKit
import PlaygroundSupport
class MyCustomView: UIView {
public let leftLabel: UILabel = UILabel(frame: .zero)
public let rightLabel: UILabel = UILabel(frame: .zero)
override init(frame: CGRect) {
super.init(frame: frame)
addSubview(leftLabel)
addSubview(rightLabel)
// background colors so we can see the view frames
backgroundColor = .cyan
leftLabel.backgroundColor = .yellow
rightLabel.backgroundColor = .green
// we want multi-line labels
leftLabel.numberOfLines = 0
rightLabel.numberOfLines = 0
// use auto-layout
leftLabel.translatesAutoresizingMaskIntoConstraints = false
rightLabel.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
// constrain to top
leftLabel.topAnchor.constraint(equalTo: topAnchor),
// constrain to left
leftLabel.leadingAnchor.constraint(equalTo: leadingAnchor),
// constrain width = 40%
leftLabel.widthAnchor.constraint(equalTo: widthAnchor, multiplier: 0.4),
// constrain to top
rightLabel.topAnchor.constraint(equalTo: topAnchor),
// constrain to right
rightLabel.trailingAnchor.constraint(equalTo: trailingAnchor),
// constrain width = 60%
rightLabel.widthAnchor.constraint(equalTo: widthAnchor, multiplier: 0.6),
// constrain bottom of view (self) to >= 0 from bottom of leftLabel
bottomAnchor.constraint(greaterThanOrEqualTo: leftLabel.bottomAnchor, constant: 0.0),
// constrain bottom of view (self) to >= 0 from bottom of rightLabel
bottomAnchor.constraint(greaterThanOrEqualTo: rightLabel.bottomAnchor, constant: 0.0),
])
leftLabel.text = "Short string"
rightLabel.text = "Short string too"
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
class MyViewController : UIViewController {
var theButton: UIButton = {
let b = UIButton()
b.setTitle("Tap Me", for: .normal)
b.translatesAutoresizingMaskIntoConstraints = false
b.backgroundColor = .red
return b
}()
var theStackView: UIStackView = {
let v = UIStackView()
v.translatesAutoresizingMaskIntoConstraints = false
v.axis = .vertical
v.spacing = 8
v.distribution = .equalSpacing
return v
}()
var myView = MyCustomView()
// on button tap, change the text in the label(s)
@objc func didTap(_ sender: Any?) -> Void {
myView.leftLabel.text = "Short string with\nA\nB\nC\nD\nE"
myView.rightLabel.text = "Short string too\nA\nB"
}
override func loadView() {
let view = UIView()
self.view = view
view.backgroundColor = .white
view.addSubview(theButton)
// constrain button to Top: 32 and centerX
NSLayoutConstraint.activate([
theButton.topAnchor.constraint(equalTo: view.topAnchor, constant: 32.0),
theButton.centerXAnchor.constraint(equalTo: view.centerXAnchor, constant: 0.0),
])
view.addSubview(theStackView)
// constrain stack view to Top: 100 and Leading/Trailing" 0
// no Bottom or Height constraint
NSLayoutConstraint.activate([
theStackView.topAnchor.constraint(equalTo: view.topAnchor, constant: 100.0),
theStackView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 0.0),
theStackView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: 0.0),
])
theStackView.addArrangedSubview(myView)
// add an action for the button tap
theButton.addTarget(self, action: #selector(didTap(_:)), for: .touchUpInside)
}
}
// Present the view controller in the Live View window
PlaygroundPage.current.liveView = MyViewController()
Upvotes: 1