Not getting correct height of UILabel in Objective-c - ios

I have string with multiple new line characters like below.
"sdfsdghhfdgdfgfdgdfghjgf
sdfsdfsdfsdfdsfdsfdsgdfgfdhghgfhfgjhf
sdfdsfdsfdsfdsfdsfdsfhhg
sdfsdfdfsd
sdfdsfdsfdsfdsfdfdsfsdf"
Now I am calculating height of label to accommodate above string. Below is my code for it.
label.numberOfLines = 0;
label.lineBreakMode = NSLineBreakByWordWrapping;
label.font = font;
label.text = labelText;
float width = label.frame.size.width;
CGSize jobDescHeightSize = [label sizeThatFits:CGSizeMake(width, CGFLOAT_MAX)];
It gives me correct height in larger device i.e. iPhone XR, iPhone 11 but it doesn't give me correct size of UILabel in iPhone 6s, iPhone 8.

The extension which solved my issue once
extension UILabel{
public var requiredHeight: CGFloat {
let label = UILabel(frame: CGRect(x: 0, y: 0, width: frame.width, height: CGFloat.greatestFiniteMagnitude))
label.numberOfLines = 0
label.lineBreakMode = NSLineBreakMode.byWordWrapping
label.font = font
label.text = text
label.attributedText = attributedText
label.sizeToFit()
return label.frame.height
}
}
Original Answer

Related

Calculate actual text frame of UILabel

i have an extension to UILabel that suppose to calculate it's frame.
func getFrameWithAlreadySetTextAndFont() -> CGRect {
let label = UILabel()
label.text = self.text
label.font = self.font
label.numberOfLines = 0
label.lineBreakMode = NSLineBreakMode.byWordWrapping
label.frame.size.width = CGFloat(MAXFLOAT)
label.frame.size.height = CGFloat(MAXFLOAT)
label.sizeToFit()
return label.frame
}
Now, i want to calculate expected text frame for my label.
let lbl = LabelSL.extraLarge()
lbl.text = "357"
let expectedLabelFrame = lbl.getFrameWithAlreadySetTextAndFont()
Ok, i got:
expected frame (0.0, 0.0, 42.5, 29.0)
That is frame of label i can see in debugger.
But what i actually want is text frame:
The same as previous, but without extra spaces. How can i get it?

resizing UILabels based on total width of text

How would I go about predicting the required width of a UILabel based on it's font size and number of characters in the label's text.
I have seen a few examples of this being done, however they are all in objective-c not swift 3.0.
I found this method but it's in objective-c and I'm having trouble implementing it.
CGFloat width = [label.text sizeWithFont:[UIFont systemFontOfSize:17.0f]].width;
Any suggestions?
If Want to Make size of UILabel Based on TextSize and TextLength then use
intrinsicContentSize.
Below is sample code for that:
lblDemo.frame.size = lblDemo.intrinsicContentSize
Here lblDemo is IBOutlet of UILabel.
override func viewDidLoad() {
super.viewDidLoad()
let screenSize = UIScreen.main.bounds
let screenWidth = screenSize.width
let text = "Size To Fit Tutorial"
let font : UIFont!
switch UIDevice.current.userInterfaceIdiom {
case .pad:
font = UIFont(name: "Helvetica", size: 35)
case .phone:
font = UIFont(name: "Helvetica", size: 50)
default:
font = UIFont(name: "Helvetica", size: 24)
}
let yourHeight = heightForLabel(text: text, font: font, width:
screenWidth)
let yourLabel : UILabel = UILabel(Frame : CGRect(x:0 ,y:0
,width:screenWidth ,height:yourHeight))
yourLabel.backgroundColor = UIColor.black
self.view.addSubviews(yourLabel)
}
//Self Sizing height ....
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.byCharWrapping
label.font = font
label.text = text
label.sizeToFit()
return label.frame.height
}
Hope, it helps
You can cast the string you are setting the label's text value to type NSString.
guard let labelText = label.text else { return }
let castString = labelText as NSString
let size: CGSize = castString.size(attributes: [NSFontAttributeName : UIFont.systemFontSize])
//you now can use size.width to apply to a desired view
You want to get width of label based on text entered. I think you will find appropriate solution here
How to calculate UILabel width based on text length?
Hope, it helps

Resize UITableViewCell Height based on UILabel Content

I've been looking into this for over a day now, and I can honestly say I am completely stumped by why this is not working as I would expect it to.
I'm trying to have a UITableViewCell expand when selected to the correct size based on the UILabel within it. I have used the following code to determine the required size for the UILabel:
extension UILabel {
func requiredHeight() -> CGFloat{
let label:UILabel = UILabel(frame: CGRectMake(0, 0, self.frame.width, CGFloat.max))
label.text = self.text
label.numberOfLines = 0
label.font = self.font
label.sizeToFit()
print("Final Size - \(label.frame.height)")
return label.frame.height + 10
}
}
My issue is, despite this size - when the Cell is resized within the 'heightForRowAtIndexPath' method - it is still not the correct size and the string is being truncated, this can be seen in the below image.
To note - I gather the required size of the cell as soon as the view has loaded and text has been populated into the UILabel.
requiredHeight = overviewLabel.requiredHeight()
if requiredHeight > overviewCell.frame.height {
expander.hidden = false
} else {
expander.hidden = true
}
Any advice on how this could be fixed will be greatly appreciated.
Try this snippet. Just provide exact name of the font and size
Swift 3.x
func requiredHeight() -> CGFloat{
let font = UIFont(name: "Helvetica", size: 16.0)
let label:UILabel = UILabel(frame: CGRect(x:0, y:0, width:200, height:CGFloat.greatestFiniteMagnitude))
label.numberOfLines = 0
label.lineBreakMode = NSLineBreakMode.byWordWrapping
label.font = font
label.text = self.text
label.sizeToFit()
return label.frame.height + //Add some space as a part of your bottom and top constraint
}
Swift 2.2
func requiredHeight() -> CGFloat{
let font = UIFont(name: "Helvetica", size: 16.0)
let label:UILabel = UILabel(frame: CGRectMake(0, 0, 200, CGFloat.max))
label.numberOfLines = 0
label.lineBreakMode = NSLineBreakMode.ByWordWrapping
label.font = font
label.text = self.text
label.sizeToFit()
return label.frame.height + //Add some space as a part of your bottom and top constraint
}
Suppose your label has top and bottom constraint as 5 and 5 respectively, them make the return statement as
return label.frame.height + 10
NOTE:- Width should be the width you want of the label. It should be according to your UITableView or UIView

How to give dynamic height to UILabel programmatically in Swift?

I have taken UIlabel which are generated dynamically using for loop, each type diff text is assign in label, I want to give UILabel size dynamically depending on text.
Is there any easy solution in to do that in Swift?
let label:UILabel = UILabel(frame: CGRectMake(x, y, width, height))
label.numberOfLines = 4
label.lineBreakMode = NSLineBreakMode.ByWordWrapping
let font = UIFont(name: "Helvetica", size: 20.0)
label.font = font
label.text = "Whatever you want the text enter here"
label.sizeToFit()
If you want to set numberOfLines according to the content of text,give your maximum lines.That is very important here.
get a label height depending on it's text, font, and width you assign to it:
func rectForText(text: String, font: UIFont, maxSize: CGSize) -> CGSize {
let attrString = NSAttributedString.init(string: text, attributes: [NSFontAttributeName:font])
let rect = attrString.boundingRectWithSize(maxSize, options: NSStringDrawingOptions.UsesLineFragmentOrigin, context: nil)
let size = CGSizeMake(rect.size.width, rect.size.height)
return size
}
let labelSize = rectForText("your text here", font: UIFont.systemFontOfSize(your font), maxSize: CGSizeMake(your label width,999))
let labelHeight = labelSize.height //here it is!
myLabel.text = "Your Label Text Here"
myLabel.textAlignment = .Natural
myLabel.numberOfLines = 0
myLabel.sizeToFit()
myLabel.frame = CGRectMake(myLabel.frame.origin.x, myLabel.frame.origin.y, 280, myLabel.frame.height)
Create Extension to calculate the height of label following method return height of the label
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: 60)
let label:UILabel = UILabel()
label.textColor=UIColor.black
label.font = UIFont(name: "Halvetica", size: 17)
label.numberOfLines = 1
label.text = item.name
label.sizeToFit()
label.frame = CGRect(x: 5, y: imageView.frame.height+10, width: 50, height:label.frame.height)
let label = UILabel()
label.backgroundColor = UIColor.greenColor()
label.text = "Hello,world.\n Just a test."
let font = UIFont.systemFontOfSize(17.0)
label.font = font
label.numberOfLines = 0;
let text = label.text! as NSString
let size = text.sizeWithAttributes([NSFontAttributeName:font])
label.frame = CGRectMake(0, 0, size.width, size.height)
You can use Auto Layout in code. See Auto Layout Guide
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
}
}
Refer: Adjust UILabel height to text
NSString(string: "hello this is a string").boundingRect(
with: CGSize(width: width, height: .greatestFiniteMagnitude),
options: .usesLineFragmentOrigin,
attributes: [.font: self],
context: nil).size
Use this method to get determine the size for you string. Put maximum height and maximum width in CGSize(widhth,height) and it will return CGSize object containing height and width. Use it according with your scenario

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!
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
}
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
For iOS7
First, you need to add contains height for UILabel
Then, modify the Relation from Equal to Greater than or Equal
Finally, change the lines of UILabel from 1 to 0
Your UILabel will automatically increase height depending on the text
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)
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
I create this extension if you want
extension UILabel {
func setSizeFont (sizeFont: CGFloat) {
self.font = UIFont(name: self.font.fontName, size: sizeFont)!
self.sizeToFit()
}
}
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
}
Just by setting:
label.numberOfLines = 0
The label automatically adjusts its height based upon the amount of text entered.
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
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
}
}
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)
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
}
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
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
}
}
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.
You can also use sizeThatFits function.
For example:
label.sizeThatFits(superView.frame.size).height
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 .

Resources