Swift label not updating frame due change of font size - swift

currently, I am creating a table view that contains an imageView as main UI item inside the cell and on top op that there is a label. Now I'm facing an issue where for long text, the frame of the label is not accurate, and for a long text it is taking a lot of space and it seems like there is a line break but there isn't, this is the issue:
Label issue
This are the properties of the label
Label properties
This is my ViewController and the constraints that I'm using
View Controller on Storyboard
Additional Details
For the Cell, I'm not adding extra code, I just have the IBOutlets and nothing more.
On the CellForRowAtIndexPath, I'm not doing additional code more than setting the image and setting the text.
Thanks

Try to change Content hugging Priority of Label

The font you've selected - Noto Nastaliq Urdu Bold - has very specific type layout properties.
Compare it with the default system font.
Using this code:
let fontDefault = UIFont.systemFont(ofSize: 17.0, weight: .bold)
guard let fontNotoBld = UIFont(name: "NotoNastaliqUrdu-Bold", size: 17) else {
fatalError("Could not create font!")
}
print("fontDefault.lineHeight:\t",fontDefault.lineHeight)
print("fontNotoBld.lineHeight:\t",fontNotoBld.lineHeight)
print()
print("fontDefault.ascender:\t",fontDefault.ascender)
print("fontNotoBld.ascender:\t",fontNotoBld.ascender)
print()
print("fontDefault.descender:\t",fontDefault.descender)
print("fontNotoBld.descender:\t",fontNotoBld.descender)
print()
print("fontDefault.xHeight:\t",fontDefault.xHeight)
print("fontNotoBld.xHeight:\t",fontNotoBld.xHeight)
print()
print("fontDefault.capHeight:\t",fontDefault.capHeight)
print("fontNotoBld.capHeight:\t",fontNotoBld.capHeight)
print()
we get this output in the debug console:
fontDefault.lineHeight: 20.287109375
fontNotoBld.lineHeight: 42.5
fontDefault.ascender: 16.1865234375
fontNotoBld.ascender: 32.368
fontDefault.descender: -4.1005859375
fontNotoBld.descender: -10.132000000000001
fontDefault.xHeight: 9.13916015625
fontNotoBld.xHeight: 9.112
fontDefault.capHeight: 11.97802734375
fontNotoBld.capHeight: 12.138000000000002
I don't know exactly why, but my assumption is that Noto Nastaliq Urdu supports many more language characters which often have very different shapes and heights.
You can either use a more standard font, or design your UI to accommodate the bigger spacing.
Edit
You could try using attributed text with line height settings. However, it will affect the top spacing of the text to a point that it may not suffice.
Here's an example with 3 labels:
top label uses default settings
second label changes maximumLineHeight to 17
third label changes maximumLineHeight to 26
let titleText = "Label with enough text to cause word wrapping onto multiple lines."
guard let fontNotoBold = UIFont(name: "NotoNastaliqUrdu-Bold", size: 17) else {
fatalError("Could not create font!")
}
// without paragraphStyle attribute
var attrString = NSMutableAttributedString(string: titleText)
attrString.addAttribute(NSAttributedString.Key.font, value: fontNotoBold, range:NSMakeRange(0, attrString.length))
label1.attributedText = attrString
// with paragraphStyle max line height: 17
let ps2 = NSMutableParagraphStyle()
ps2.maximumLineHeight = 17
attrString = NSMutableAttributedString(string: titleText)
attrString.addAttribute(NSAttributedString.Key.font, value: fontNotoBold, range:NSMakeRange(0, attrString.length))
attrString.addAttribute(NSAttributedString.Key.paragraphStyle, value:ps2, range:NSMakeRange(0, attrString.length))
label2.attributedText = attrString
// with paragraphStyle max line height: 26
let ps3 = NSMutableParagraphStyle()
ps3.maximumLineHeight = 26
attrString = NSMutableAttributedString(string: titleText)
attrString.addAttribute(NSAttributedString.Key.font, value: fontNotoBold, range:NSMakeRange(0, attrString.length))
attrString.addAttribute(NSAttributedString.Key.paragraphStyle, value:ps3, range:NSMakeRange(0, attrString.length))
label3.attributedText = attrString
Here's the result:
With a little more experimentation, such as adding a newline ("\n") at the beginning, you might be able to get it to a satisfactory appearance.

Related

Autoshrink fontsize of UILabeltext siwft

I have a multiline UILabel text which expands dynamically according to the text length. I have setup proper auto layout in storyboard and grows bigger if the text is lengthy.
But i want to reduce the font size to 24 if its 2-line and to 20 if its 3-line text.
If text is single line then, font size should be 34.
I tried minimum font scale = 20/34 = .58
but no use. Please suggest a solution
You could use a switch statement to determine the font size when a certain number of lines have been after changing the label's text.
Using the actualNumberOfLines() algorithm from https://stackoverflow.com/a/60993649/12783209 allows you to redeclare the font for this label whenever necessary.
func changeFontSizeIfNeeded(on label: inout UILabel){
switch label.actualNumberOfLines{
case 2:
label.font = label.font.withSize(24)
case 3:
label.font = label.font.withSize(20)
default:
//Change this to be the default font size
label.font = label.font.withSize(30)
}
}
And add this extension to your project:
extension UILabel{
func actualNumberOfLines()-> Int {
// You have to call layoutIfNeeded() if you are using autoLayout
self.layoutIfNeeded()
let myText = self.text! as NSString
let rect = CGSize(width: self.bounds.width, height: CGFloat.greatestFiniteMagnitude)
let labelSize = myText.boundingRect(with: rect, options: .usesLineFragmentOrigin, attributes: [NSAttributedString.Key.font: self.font as Any], context: nil)
return Int(ceil(CGFloat(labelSize.height) / self.font.lineHeight))
}
}

Multiline multicolor attributed text in swift

How can I build something like this using attributed text? I tried adding line feed (\n), it didn't work, just displayed first line and cropped next two, removing \n will display two parts in single line:
let mutableAttributedString = NSMutableAttributedString()
let regularAttribute = [NSAttributedStringKey.font: UIFont(name: "Avenir-Light", size: 45.0), NSAttributedStringKey.foregroundColor: UIColor.yellow]
let boldAttribute = [NSAttributedStringKey.font: UIFont(name: "Avenir-Light", size: 25.0), NSAttributedStringKey.foregroundColor: UIColor.white]
let mutableAttributedString2 = NSMutableAttributedString()
let boldAttributedString = NSAttributedString(string: "person", attributes: boldAttribute)
let regularAttributedString = NSAttributedString(string: "\(self.requestCount)", attributes: regularAttribute)
mutableAttributedString2.append(boldAttributedString)
mutableAttributedString2.append(NSAttributedString(string: "\n"))
mutableAttributedString2.append(regularAttributedString)
self.btnStatsPeople.setAttributedTitle(mutableAttributedString2, for: .normal)
UILabel has one line by default.
This property controls the maximum number of lines to use in order to
fit the label’s text into its bounding rectangle. The default value
for this property is 1. To remove any maximum limit, and use as many
lines as needed, set the value of this property to 0.
UIButton creates default UILabel. So using 0 lines is a solution for your problem:
self.btnStatsPeople.titleLabel?.numberOfLines = 0

Is it possible to Change the Regular font to Bold of UILable text?

I have a Label with custom font Unica One-Regular. Since, it is not available in bold font, I am getting problem to make it bold. Is there any way to make it bold?. Here is the font link.
https://fonts.google.com/specimen/Unica+One?selection.family=Unica+One
Thanks in advance.
Sorry I’m on my iPhone but,
Please check the exact name of the font on Xcode, but this code should answer your question :
let attrs:[String:AnyObject] = [NSFontAttributeName: UIFont(name: "Unica One-Bold", size: 12)!]
let boldString = NSMutableAttributedString(string: "text", attributes:attrs)
let lbl = UILabel()
lbl.attributedText = boldString
There is a more recent answer to this question at Is it possible to increase the boldness of the font if the bold font file is not available?.
Short summary: if you have a list of font attributes, you can add a negative stroke width. For example (in Swift):
import AppKit
guard let chosenFont = NSFont(name: "VTypewriter Underwood", size: 24) else {
print("No such font")
exit(1)
}
var fontAttributes = [
NSAttributedString.Key.font:chosenFont,
NSAttributedString.Key.strokeWidth:NSNumber(value:-3.0)
]
let fakelyBoldedText = NSAttributedString(string:"Hello World", attributes:fontAttributes)
This is not optimal; it isn’t really bolding. But with low values for the stroke width (in my experiments, from about -3 to -5, possibly relative to the font width), it does look bolded.

Attributed string cutting and displaying single word into two lines on UILabel

I'm creating attributed text using following attributes,
func attributedString(font: UIFont, contentColor: UIColor, alignment: NSTextAlignment) -> NSAttributedString {
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineSpacing = 0.6
paragraphStyle.lineHeightMultiple = 0.8
paragraphStyle.alignment = alignment
paragraphStyle.lineBreakMode = .byWordWrapping
let lineSpacingAttribute: [NSAttributedStringKey: Any] = [NSAttributedStringKey.paragraphStyle: paragraphStyle, NSAttributedStringKey.font: font, NSAttributedStringKey.foregroundColor: contentColor]
let attributedString = NSAttributedString(string: self, attributes: lineSpacingAttribute)
return attributedString
}
I'm displaying this text on UILabel inside a custom tableViewCell. But, it is cutting a single word into two (cutting last letter of a word and displaying it on next line). I've set the numberOfLines to zero, and preferredMaxLayoutWidth for label. And I'm using a custom font.
This problem is happening on small screens only, iPhone SE and iPhone 5S simulators. But, on other simulators it is displaying correctly. Could you please help me to figure out what is wrong in this?
Thanks!
From Apple doc:
var preferredMaxLayoutWidth: CGFloat
This property affects the size of the label when layout constraints are applied to it. During layout, if the text extends beyond the width specified by this property, the additional text flows to one or more new lines, increasing the height of the label.
Depending on your text you can use the adjustsFontSizeToFitWidth property with the minimumScaleFactor property

Multi-line UILabel not resizing text when using attributedText

I am trying to make a very custom UILabel. When viewDidAppear is called, the UILabel's attributedText property is set. This UILabel needs to be 2 lines. I have minimumFontSize set to 7 and numberOfLines set to 2 in storyboard.
Here is my code:
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineSpacing = 8.0
paragraphStyle.alignment = NSTextAlignment.Right
let name = idea?.valueForKey("name") as! String
let text = "You submitted your name " + name
let attrString = NSMutableAttributedString(string: text)
attrString.addAttribute(NSFontAttributeName, value: UIFont.systemFontOfSize(12.00), range: NSMakeRange(0,attrString.length))
attrString.addAttribute(NSParagraphStyleAttributeName, value: paragraphStyle, range: NSMakeRange(0, attrString.length))
attrString.addAttribute(NSForegroundColorAttributeName, value: UIColor(r: 84, g: 105, b: 121, a: 1.0), range: NSMakeRange(0, 3))
attrString.addAttribute(NSForegroundColorAttributeName, value: UIColor(r: 84, g: 105, b: 121, a: 1.0), range: NSMakeRange(attrString.length - name.characters.count, name.characters.count))
submittedComment.attributedText = attrString
ISSUE: The newly set text for the UILabel is not resized to fit within the UILabel.
Am I missing something? It seems like every new major iOS update changes the way this occurs. Thanks!
Solved:
There were two main errors I found:
It seems that setting the lineSpacing on an NSMutableAttributedString will hide some of the text. From what I've tested, it doesn't seem like the autoresizing feature of UILabel considers this when resizing.
My UILabel had a set width and height. The issue here was setting the height, which wasn't necessary in my case. Once I removed it, my attributedText was no longer hidden.
hope this helps!
Sometimes it's enough to just layout the view again to consider the lineSpacing. For example in my case I had to do the following:
let cell = tableView.dequeueReusableCell(withIdentifier: R.reuseIdentifier.descriptionCell, for: indexPath)!
cell.label.text = "Long text with multiple line breaks."
+ " In the nib the attributedText style including the paragaphStyle is configured"
+ " so just set the text here"
cell.layoutIfNeeded()
return cell