Bounding rect of multiline string in UILabel swift - ios

I have been trying for hours now to find the boundingRect of a string in a UILabel I have, but nothing seems to be working.
From what I understand, boundingRect returns the size of the actual text in the label, not the label's size or something like that. This is true, right?
I have a UILabel called messageLabel which contains some text that wraps to an unlimited number of lines.
The code I have now is this:
let labelRect = (message as NSString).boundingRect(with: messageLabel.frame.size,
options: .usesLineFragmentOrigin,
attributes: [NSFontAttributeName : messageLabel.font],
context: nil)
Unfortunately, this returns totally wrong dimensions for my text.
What is the correct way to return the dimensions of text in a multiline UILabel?

Use:
let sizeToFit = CGSize(width: messageLabel.frame.size.width,
height: CGFloat.greatestFiniteMagnitude)
let textSize = messageLabel.sizeThatFits(sizeToFit)
Anyway, the way you did it should work as well (you can see on playground both functions return same size):
I've added a sample view to the playground, so you can see, the label has black border, and the text fits inside, and is smaller than label. Size is computer properly with both sizeToFit and boundingRect methods (but boundingRect returns not rounded values). I've use this computed size to create a green background view under the text, and it fits it properly.

I think you need to Try this
let messageLabel = UILabel(frame: CGRect(x: 0, y: 0, width: _screenSize.width - 30, height: 5))
messageLabel.font = self.txtDescription.font
messageLabel.numberOfLines = 0
messageLabel.text = "Your Massage"
messageLabel.numberOfLines = 0
messageLabel.sizeToFit()
print(messageLabel.frame.size.height)
Remove all code Just try this Hope it will wirk

Related

Text not vertically centered in UILabel for some fonts

I want the text to always be vertically centered. It doesn't work for some specific fonts such as "DamascusSemiBold", What is the solution?
let label = VerticalLabel(frame: CGRect(x: 10, y: 100, width: 300, height: 50))
label.layer.borderColor = UIColor.red.cgColor
label.layer.borderWidth = 1
label.text = "Text Sticker"
label.font = UIFont(name: "DamascusSemiBold", size: 30)
label.numberOfLines = 0
label.textColor = .white
label.textAlignment = .center
self.view.addSubview(label)
public override func textRect(forBounds bounds: CGRect, limitedToNumberOfLines numberOfLines: Int) -> CGRect {
var textRect = super.textRect(forBounds: bounds, limitedToNumberOfLines: numberOfLines)
print(textRect, bounds)
textRect.origin.y = bounds.origin.y + (bounds.size.height - textRect.size.height) * 0.5
print(textRect)
return textRect
}
public override func drawText(in rect: CGRect) {
let actualRect = self.textRect(forBounds: rect, limitedToNumberOfLines: self.numberOfLines)
super.drawText(in: actualRect)
}
It's not centered, just top!
I know there are a lot of threads similar to this, but I've read all of them (as far as I can tell) and haven't seen the same problem I'm having.
I'm trying to get all of the text to show in a label VERTICALLY.
Let me explain - Fonts are not always created the same way, so while their total height may be the same (24pts, for example). However, the Ascender and Descender vary widely - one font may be mostly above the baseline, while another is mostly below. Therefore, the same text, with different fonts may not always show in the same view/label.
The first is Helvetica-Bold 300pts. The second is Apple Gothic 300pts.
Notice how the bottom of the "g" is cut off with Helvetica (and many other fonts too - try it, you'll see).
So my issue is this: I'd like to be able to see the entire text, regardless of the font. If the text in the "Helvetica" example could be moved up (and centered) within the label, it would solve my problem. To make it easier, I only need to display a single line.
Unfortunately, none of the solutions I've seen involve the descenders and ascenders of the font and figuring out how to draw the text within a Rect and not have it cropped. Note that the "VerticalAlignment" solutions in various threads don't fix this particular problem.
I calculate boundRect for attributedString and update the frame of label, and center text vertically
super.drawText(in: rect.inset(by: UIEdgeInsets(top: -(font.ascender - font.capHeight), left: 0, bottom: font.descender, right: 0)))
Above code cuts descender even though center vertically, how can I center text vertically without cutting of ascender, descender?
Screenshot
Does anyone have any ideas or solutions for this?
f you have a label with longer text that will make more than one line, set numberOfLines to 0 (zero here means an unlimited number of lines).
label.numberOfLines = 0

NSAttributedString Drawing - How Many Lines?

I am drawing text within a PDF using this method:
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.alignment = .center
paragraphStyle.lineBreakMode = .byWordWrapping
let textAttributes = [
NSAttributedString.Key.paragraphStyle: paragraphStyle,
NSAttributedString.Key.font: UIFont(name: "MySpecialFont", size: 16)!,
NSAttributedString.Key.foregroundColor: UIColor.black
]
let attributedText = NSAttributedString(
string: myTextArray.first,
attributes: textAttributes
)
let textRect = CGRect(
x: 400,
y: 40,
width: 80,
height: 40
)
attributedText.draw(in: textRect)
Above draws the text fine. However, sometimes, the string passed on to it seem to be too long and go on for 3 lines instead of 2. In these cases, I want to textRect to be taller. Basically to know how many lines it would take so textRect could be adjusted.
There are several functions within NSAttributedString that gives string length, but thats the length if it was in a single line.
Is there a way to know how many lines the final attributedText would take inside textRect?
Use NSAttributedString.boundingRect(with:options:context:) to compute the size required. You should pass .usesLineFragmentOrigin as an option so that it'll compute it for multiple lines. Pass the width you want; the height doesn't really matter, because it'll expand the height to contain the full string, and you can use that to work out your final rectangle.
That said, from your description, it sounds like you can just make the height very large (10,000 is the usual value; but maybe you want to just give room for three lines). Since you're just drawing here; it shouldn't matter if the available rect is taller than required. It only matters if it's shorter.

Word Wrap Occurs Inconsistently in UILabel

I have a UILabel that is designed to expand in height when the width of the text's CGSize is greater than the width of the label. I accomplish that with this code:
func viewHeight(_ locationName: String) -> CGFloat {
let locationName = tappedLocation[0].name
var size = CGSize()
if let font = UIFont(name: ".SFUIText", size: 17.0) {
let fontAttributes = [NSAttributedStringKey.font: font]
size = (locationName as NSString).size(withAttributes: fontAttributes)
}
let normalCellHeight = horizontalStackViewHeightConstraint.constant
let extraLargeCellHeight = horizontalStackViewHeightConstraint.constant + 20.33
let textWidth = ceil(size.width)
let cellWidth = ceil(nameLabel.frame.width)
if textWidth > cellWidth {
return extraLargeCellHeight
} else {
return normalCellHeight
}
}
Lines = 0 and line break style = Word Wrap:
The label lives inside a vertical stackView, and is constrained to its top, leading and trailing edges and a stackView beneath it. The height of the label and the UIView properly expand in height when the CGSize width of the text is longer than the width of the label. All well and good.
However, the words do not wrap consistently. This behavior is intentional:
Bobby Mao's Chinese Kitchen & Bar:
XL cell. Width: 184.0,
Text width: 287.0
This behavior is not (why isn't "steak" on the prior line?):
Ruth's Chris Steak House:
XL cell. Width: 184.0,
Text width: 204.0
And neither is this (why didn't Gina wrap if it's over the label width parameter?):
Ristorante Mamma Gina:
XL cell. Width: 184.0,
Text width: 191.0
I have also set a temporary background color on my label to ensure that it does, in fact correspond to the intended width. The label in this example creates another line when the label's width is exceeded, but the text does not wrap:
I have read the other entries on Stack Overflow about word wrapping. I don't believe this is a duplicate. I do not have trouble creating two lines for my text. I don't have trouble with word wrapping occurring. I have trouble with how and when it is occurring.
I think the intent is clear... what am I missing?

UILabel on second line if the content doesn't fit in the view's first line

The best way to describe my situations is with images. What I have is a view which contains several UILabels and UIImage. The red box is a UILabel and if the content is too big it should go to the second line.
From the storyboard I have a working case when the content fits but the problem is that I am not sure how to handle the case when the last (red box) should go to the second line. I am using autolayout and cartography.
If someone can point me to the right direction I will be very grateful.
First calcululate width of text as per your current label's position.
If text width is more than current label's width then see my answer from below link:
Auto Layout how to move the view2 from right to the bottom?
Calculate width:
func widthForView1(_ text:String, font:UIFont, height:CGFloat) -> CGFloat
{
let label:UILabel = UILabel(frame: CGRect(x: 0, y: 0, width: your_label_width, height: your_lable_height))
label.numberOfLines = 0
label.lineBreakMode = NSLineBreakMode.byWordWrapping
label.text = text
label.font = font
label.sizeToFit()
return label.frame.width
}
You cannot do that with constraints only. To change the entire position of the element on the screen, you need to do it programmatically.
Use of tag View can solve this issue. TagListView is an external library.
When u add a view as subclass of taglistView, its height automatically increases accordingly.
ADD this to pod file : pod 'TagListView'
func addTags() {
let str1 = "Hi"
tagListView.addTag(str1)
let str2 = "Helloo"
tagListView.addTag(str2)
let str3 = "How Are u ? "
tagListView.addTag(str2)
tagListView.isUserInteractionEnabled = false
}

Dynamically adjust width of UILabel in Swift 3

I'm trying to get my UILabel to get wider (along with its border and background color) as the content gets more - and then less when the content is reduced.
Where do I go to get started, I've looked at the Attributes Inspectors and it looks like this can only be done with code (which I'm fine with).
I thought adding two labels in a horizontal stack would do the trick, but it doesn't update in real-time (it will update the label only on launch).
Try using :
myLabel.sizeToFit()
on your label.This should update the label's frame to fit the content.
let label:UILabel = UILabel()
label.textColor=UIColor.black
label.font = UIFont(name: "Halvetica", size: 17)
label.numberOfLines = 1
label.text = "your string"
label.sizeToFit()
label.frame = CGRect(x: 5, y: imageView.frame.height+10, width: label.frame.width, height:label.frame.height)

Resources