trusk
trusk

Reputation: 1703

Programmatically create UIView with size based on subviews(labels)

I have a scenario where I'm needed to create an UIView completely programatically. This view is displayed as an overlay over a video feed and it contains 2 UILabels as subviews.

These labels can have varying widths and heights so I don't want to create a fixed frame for the UIView or the labels.

I've done this with programatic constrains without issue, but the problem is that the views are glitching when moving the phone and the framework that I'm using that does the video feed recommends not to use autolayout because of this exact problem.

My current code:

So my problem is now: how can I achieve the same behavior, without using autolayout?

Edit: here is a video of the behavior https://streamable.com/s/4zusq/dvbgnb

Edit 2: The solution is based on Mahgol Fa's answer and using a stack view or vertical positioning in order not to set the frame for the individual labels. So the final implementation is

private func loadUI() {
        titleLabel?.removeFromSuperview()
        distanceLabel?.removeFromSuperview()

        let label = UILabel()
        label.font = titleViewFont
        label.numberOfLines = 0
        label.textColor = UIColor.white
        label.textAlignment = .center
        self.titleLabel = label

        distanceLabel = UILabel()
        distanceLabel.textColor = .cbPPGreen
        distanceLabel.font = subtitleViewFont
        distanceLabel.textAlignment = .center

        label.translatesAutoresizingMaskIntoConstraints = false
        distanceLabel.translatesAutoresizingMaskIntoConstraints = false

        if let annotation = annotation as? BikeStationAR {
            let title = annotation.address
            let subtitle = String(format: "%.2f km", annotation.distanceFromUser / 1000)

            let fontAttributeTitle = [NSAttributedString.Key.font: titleViewFont]
            let titleSize = title.size(withAttributes: fontAttributeTitle)

            let fontAttributeSubtitle = [NSAttributedString.Key.font: subtitleViewFont]
            let subtitleSize = annotation.address.size(withAttributes: fontAttributeSubtitle)

            titleLabel?.text = title
            distanceLabel?.text = subtitle

            let stackView = UIStackView(frame: CGRect(x: 0, y: 0, width: titleSize.width + 5, height: titleSize.height + subtitleSize.height + 5))
            stackView.axis = .vertical
            stackView.distribution = .fillProportionally
            stackView.alignment = .fill
            stackView.addArrangedSubview(titleLabel ?? UIView())
            stackView.addArrangedSubview(distanceLabel)

            frame = stackView.bounds
            addSubview(stackView)
        }
    }

Upvotes: 1

Views: 268

Answers (1)

Mahgolsadat Fathi
Mahgolsadat Fathi

Reputation: 3325

This way you can get the width of your lablels texts:

let fontAttributes1= [NSAttributedStringKey.font: your declared font in your code]
   let size1 = (“your string” as String).size(withAttributes: fontAttributes1)
let fontAttributes2= [NSAttributedStringKey.font: your declared font in your code]
   let size2 = (“your string” as String).size(withAttributes: fontAttributes2)

Then :

YourView.frame = CGRect( width: size1.width + size2.width + some spacing , height : ....)

Upvotes: 1

Related Questions