ChatGPT解决这个技术问题 Extra ChatGPT

Adjust UILabel height to text

I have some labels which I want to adjust their height to the text, this is the code I wrote for this now

func heightForView(text:String, font:UIFont, width:CGFloat) -> CGFloat{
    let label:UILabel = UILabel(frame: CGRectMake(0, 0, width, CGFloat.max))
    label.numberOfLines = 0
    label.lineBreakMode = NSLineBreakMode.ByWordWrapping
    label.font = font
    label.text = text

    label.sizeToFit()
    return label.frame.height
}

EDIT:

The issue was not in this piece of code, so my fix is in the question itself. It might still be useful for others!

Take a look at NSString UIKit additions, there are methods there to calculate the size as you need without creating a UILabel.
@VladimirGritsenko the 'sizeWithFont' methods are unavailable in Swift :(
I admit I'm not an expert on Swift, but I believe you can add your own bridging methods. Would still be worth it over creating UILabel to calculate size.
@TheBurgerShot sizeWithFont may not be available for Swift String but it is available on NSString You should still be able to call it on that.
In the end, the error was something different and had nothing to do with this method. Though this might still be helpful for others.

C
Community

I've just put this in a playground and it works for me.

Updated for Swift 4.0

import UIKit

 func heightForView(text:String, font:UIFont, width:CGFloat) -> CGFloat{
    let label:UILabel = UILabel(frame: CGRectMake(0, 0, width, CGFloat.greatestFiniteMagnitude))
    label.numberOfLines = 0
    label.lineBreakMode = NSLineBreakMode.byWordWrapping
    label.font = font
    label.text = text

    label.sizeToFit()
    return label.frame.height
}

let font = UIFont(name: "Helvetica", size: 20.0)

var height = heightForView("This is just a load of text", font: font, width: 100.0)

Swift 3:

func heightForView(text:String, font:UIFont, width:CGFloat) -> CGFloat{
    let label:UILabel = UILabel(frame: CGRect(x: 0, y: 0, width: width, height: CGFloat.greatestFiniteMagnitude))
    label.numberOfLines = 0
    label.lineBreakMode = NSLineBreakMode.byWordWrapping
    label.font = font
    label.text = text
    label.sizeToFit()

    return label.frame.height
}

https://i.stack.imgur.com/EGSY4.png


this works fine for mee too in playground, the error does not seem to occur at this specific place, when i remove the usages of this method it is gonna whine about some println's or just a line with only comments (then it says EXC_BAD_ACCESS code=2 as well)
It works in a playground, but no sizing occurs as desired inside of a view controller in XCode 6.1
I am a little hesitant to create a new UILabel per sizing; if this method is used inside layoutSubviews with the tendency to be invoked multiple times per complete layout, the extra object creation may introduce noticeable delays, especially during scrolling.
let textRect = textString.boundingRectWithSize(CGSizeMake(320, 2000), options: .UsesLineFragmentOrigin, attributes: textAttributes, context: nil)
I am unable to call this function in my view controller...Can you suggest me what could be the possible reason?
L
Linh

If you are using AutoLayout, you can adjust UILabel height by config UI only.

For iOS8 or above

Set constraint leading/trailing for your UILabel

And change the lines of UILabel from 1 to 0

https://i.stack.imgur.com/crkyd.png

For iOS7

First, you need to add contains height for UILabel

Then, modify the Relation from Equal to Greater than or Equal

https://i.stack.imgur.com/kQbYt.png

Finally, change the lines of UILabel from 1 to 0

https://i.stack.imgur.com/crkyd.png

Your UILabel will automatically increase height depending on the text


And if the label is inside a cell. When and how would you increase the cell height accordingly?
@oyalhi, if your label is inside a tableview cell, please see my other post stackoverflow.com/a/36277840/5381331
This worked perfectly for me! Setup the constraints, and it will work properly!
not working for me...the word "Label" in a UILabel makes height=20. It remains 20 after this setting.
No idea what "add contains height for UILabel" means, and there is no "Height Constraint" section in UIBuilder with First Item (pictured)??
d
dimpiax

I have the strong working solution.

in layoutSubviews:

title.frame = CGRect(x: 0, y: 0, width: bounds.width, height: 0)
title.sizeToFit()
title.frame.size = title.bounds.size

in text setter:

title.text = newValue
setNeedsLayout()

UPD. of course with this UILabel settings:

title.lineBreakMode = .byWordWrapping
title.numberOfLines = 0

proved.. thanks!
Y
YannSteph

I create this extension if you want

extension UILabel {
    func setSizeFont (sizeFont: CGFloat) {
        self.font =  UIFont(name: self.font.fontName, size: sizeFont)!
        self.sizeToFit()
    }
}

N
Naresh

In swift 4.1 and Xcode 9.4.1

Only 3 steps

Step 1)

//To calculate height for label based on text size and width
func heightForView(text:String, font:UIFont, width:CGFloat) -> CGFloat {
    let label:UILabel = UILabel(frame: CGRect(x: 0, y: 0, width: width, height: CGFloat.greatestFiniteMagnitude))
    label.numberOfLines = 0
    label.lineBreakMode = NSLineBreakMode.byWordWrapping
    label.font = font
    label.text = text

    label.sizeToFit()
    return label.frame.height
}

Step 2)

//Call this function
let height = heightForView(text: "This is your text", font: UIFont.systemFont(ofSize: 17), width: 300)
print(height)//Output : 41.0

Step 3)

//This is your label
let proNameLbl = UILabel(frame: CGRect(x: 0, y: 20, width: 300, height: height))
proNameLbl.text = "This is your text"
proNameLbl.font = UIFont.systemFont(ofSize: 17)
proNameLbl.numberOfLines = 0
proNameLbl.lineBreakMode = .byWordWrapping
infoView.addSubview(proNameLbl)

L
LeftyT

based on Anorak's answer, I also agree with Zorayr's concern, so I added a couple of lines to remove the UILabel and return only the CGFloat, I don't know if it helps since the original code doesn't add the UIabel, but it doesn't throw error, so I'm using the code below:

func heightForView(text:String, font:UIFont, width:CGFloat) -> CGFloat{

    var currHeight:CGFloat!

    let label:UILabel = UILabel(frame: CGRectMake(0, 0, width, CGFloat.max))
    label.numberOfLines = 0
    label.lineBreakMode = NSLineBreakMode.ByWordWrapping
    label.font = font
    label.text = text
    label.sizeToFit()

    currHeight = label.frame.height
    label.removeFromSuperview()

    return currHeight
}

J
Jordan Amman

Just by setting:

label.numberOfLines = 0

The label automatically adjusts its height based upon the amount of text entered.


This does not make the UILabel to adjust it's height.
P
Philipp Otto

The solution suggested by Anorak as a computed property in an extension for UILabel:

extension UILabel
{
var optimalHeight : CGFloat
    {
        get
        {
            let label = UILabel(frame: CGRectMake(0, 0, self.frame.width, CGFloat.max))
            label.numberOfLines = 0
            label.lineBreakMode = self.lineBreakMode
            label.font = self.font
            label.text = self.text

            label.sizeToFit()

            return label.frame.height
         }
    }
}

Usage:

self.brandModelLabel.frame.size.height = self.brandModelLabel.optimalHeight

Cannot assign to property: 'height' is a get-only property.
L
Lirik

Following on @Anorak answer, i added this extension to String and sent an inset as a parameter, because a lot of times you will need a padding to your text. Anyway, maybe some you will find this usefull.

extension String {

    func heightForWithFont(font: UIFont, width: CGFloat, insets: UIEdgeInsets) -> CGFloat {

        let label:UILabel = UILabel(frame: CGRectMake(0, 0, width + insets.left + insets.right, CGFloat.max))
        label.numberOfLines = 0
        label.lineBreakMode = NSLineBreakMode.ByWordWrapping
        label.font = font
        label.text = self

        label.sizeToFit()
        return label.frame.height + insets.top + insets.bottom
    }
}

label.lineBreakMode = NSLineBreakMode.ByWordWrapping this line helped me thanks.
C
Collin

Here is how to calculate the text height in Swift. You can then get the height from the rect and set the constraint height of the label or textView, etc.

let font = UIFont(name: "HelveticaNeue", size: 25)!
let text = "This is some really long text just to test how it works for calculating heights in swift of string sizes. What if I add a couple lines of text?"

let textString = text as NSString

let textAttributes = [NSFontAttributeName: font]

let textRect = textString.boundingRectWithSize(CGSizeMake(320, 2000), options: .UsesLineFragmentOrigin, attributes: textAttributes, context: nil)

S
Shubham bairagi

just call this method where you need dynamic Height for label

func getHeightforController(view: AnyObject) -> CGFloat {
    let tempView: UILabel = view as! UILabel
    var context: NSStringDrawingContext = NSStringDrawingContext()
    context.minimumScaleFactor = 0.8

    var width: CGFloat = tempView.frame.size.width

    width = ((UIScreen.mainScreen().bounds.width)/320)*width

    let size: CGSize = tempView.text!.boundingRectWithSize(CGSizeMake(width, 2000), options:NSStringDrawingOptions.UsesLineFragmentOrigin, attributes: [NSFontAttributeName: tempView.font], context: context).size as CGSize

    return size.height
}

7
7ur7l3

Swift 4.0

self.messageLabel = UILabel(frame: CGRect(x: 70, y: 60, width:UIScreen.main.bounds.width - 80, height: 30)

messageLabel.text = message

messageLabel.lineBreakMode = .byWordWrapping //in versions below swift 3 (messageLabel.lineBreakMode = NSLineBreakMode.ByWordWrapping)    
messageLabel.numberOfLines = 0 //To write any number of lines within a label scope

messageLabel.textAlignment = .center

messageLabel.textColor = UIColor.white

messageLabel.font = messageLabel.font.withSize(12)

messageLabel.sizeToFit()

Blockquote NSParagraphStyle.LineBreakMode, apply to entire paragraphs, not words within paragraphs.This property is in effect both during normal drawing and in cases where the font size must be reduced to fit the label’s text in its bounding box. This property is set to byTruncatingTail by default.

This link describes the storyboard way of doing the same


Code-only answers are not considered good practice. Please consider adding some explanations on how your answer addresses the question.
P
Patrick J.

Swift 4.0

Instead of calculating the text/label height, I just resize the label after inserting the (dynamic) text.

Assuming that myLabel is the UILabel in question:

let myLabel = UILabel(frame: CGRect(x: 0, y: 0, width: *somewidth*, height: *placeholder, e.g. 20*))
myLabel.numberOfLines = 0
myLabel.lineBreakMode = .byWordWrapping
...

And now comes the fun part:

var myLabelText: String = "" {
   didSet {
      myLabel.text = myLabelText
      myLabel.sizeToFit()
   }
}

佚名

The Swift 4.1 extension method to calculate label height:

extension UILabel {

    func heightForLabel(text:String, font:UIFont, width:CGFloat) -> CGFloat {
        let label:UILabel = UILabel(frame: CGRect(x: 0, y: 0, width: width, height: CGFloat.greatestFiniteMagnitude))
        label.numberOfLines = 0
        label.lineBreakMode = NSLineBreakMode.byWordWrapping
        label.font = font
        label.text = text

        label.sizeToFit()
        return label.frame.height
    }

}

E
Egzon P.

Swift 5, XCode 11 storyboard way. I think this works for iOS 9 and higher. You want for example "Description" label to get the dynamic height, follow the steps:

1) Select description label -> Go to Attributes Inspector (pencil icon), set: Lines: 0 Line Break: Word Wrap

2) Select your UILabel from storyboard and go to Size Inspector (ruler icon), 3) Go down to "Content Compression Resistance Priority to 1 for all other UIView (lables, buttons, imageview, etc) components that are interacting with your label.

For example, I have UIImageView, Title Label, and Description Label vertically in my view. I set Content Compression Resistance Priority to UIImageView and title label to 1 and for description label to 750. This will make a description label to take as much as needed height.


F
Fitsyu

You can also use sizeThatFits function.

For example:

label.sizeThatFits(superView.frame.size).height


R
Ranjeet Raushan

To make label dynamic in swift , don't give height constarint and in storyboard make label number of lines 0 also give bottom constraint and this is the best way i am handling dynamic label as per their content size .