Swift - How to Resize a Uiview Based on Its Uilabel Size (That Is Inside)

Auto resize the UIView based on UILabel's content through Auto Layout

You may want to try the following code,

Create a method sizeHeaderToFit and which returns height of the UIView based on its content's height.

private func sizeHeaderToFit(headerView: UIView?) -> CGFloat {
guard let headerView = headerView else {
return 0.0
}

headerView.setNeedsLayout()
headerView.layoutIfNeeded()

let height = headerView.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize).height

return height
}

Then you can call the above method from the respective code,

sizeHeaderToFit(headerView: yourView)

In ORABannerView class, add override layoutSubviews,

override func layoutSubviews() {
super.layoutSubviews()
bannerText.preferredMaxLayoutWidth = bannerText.bounds.width
}

And in xib file, keep the constraints to its superview rather than safe area for code optimisation. [Optional]

Hope it helps.

UIView resize to fit labels inside of it

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):

Sample Image

If you constrain the Bottom of your custom view to the Bottom of each label at greaterThanOrEqualTo you can keep the labels "top-aligned":

Sample Image

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()

Resize UIView in XIB depending on subviews size

Never mind, turns out the view does size itself already, because I constrained the height of the button and the little title stack view at the top and not the middle stack view. Don't really know how this works, but it does!

Adjust UILabel height depending on the text

sizeWithFont constrainedToSize:lineBreakMode: is the method to use. An example of how to use it is below:

//Calculate the expected size based on the font and linebreak mode of your label
// FLT_MAX here simply means no constraint in height
CGSize maximumLabelSize = CGSizeMake(296, FLT_MAX);

CGSize expectedLabelSize = [yourString sizeWithFont:yourLabel.font constrainedToSize:maximumLabelSize lineBreakMode:yourLabel.lineBreakMode];

//adjust the label the the new height.
CGRect newFrame = yourLabel.frame;
newFrame.size.height = expectedLabelSize.height;
yourLabel.frame = newFrame;


Related Topics



Leave a reply



Submit