I am adding a UILabel to a view with the following layout requirements:
My label's properties layout constraints seem to describe this adequately:
let label = UILabel()
label.backgroundColor = UIColor.yellowColor()
label.font = UIFont.systemFontOfSize(100)
label.numberOfLines = 0
label.textAlignment = .Center
label.adjustsFontSizeToFitWidth = true
label.text = "What's Brewing in PET/CT: CT and MR Emphasis"
label.setTranslatesAutoresizingMaskIntoConstraints(false)
view.addSubview(label)
view.addConstraint(NSLayoutConstraint(item: label, attribute: .CenterX, relatedBy: .Equal, toItem: view, attribute: .CenterX, multiplier: 1, constant: 0))
view.addConstraint(NSLayoutConstraint(item: label, attribute: .CenterY, relatedBy: .Equal, toItem: view, attribute: .CenterY, multiplier: 1, constant: 0))
view.addConstraint(NSLayoutConstraint(item: label, attribute: .Left, relatedBy: .Equal, toItem: view, attribute: .Left, multiplier: 1, constant: 60))
view.addConstraint(NSLayoutConstraint(item: label, attribute: .Right, relatedBy: .Equal, toItem: view, attribute: .Right, multiplier: 1, constant: -60))
view.addConstraint(NSLayoutConstraint(item: label, attribute: .Height, relatedBy: .LessThanOrEqual, toItem: nil, attribute: .NotAnAttribute, multiplier: 1, constant: 450))
However, I am finding that with longer content like that below, the label is displayed with some unexpected margins:
This is unacceptable since any views placed directly above or below the label will have a gap.
Based on the discussion below, my working theory is that the layout engine is calculating the size based on the font size of 100, without taking into account the subsequent scaling when the content is longer.
How can I meet the layout requirements listed above (ideally without using any deprecated methods)?
Here's a test project to play with.
I took a look at your project and I might have found out a solution to your problem.
I added the following to the label setup:
label.minimumScaleFactor = 0.5
This is how the view looks like after my change:
There is no more spacing on top of the label.
Hope this helps you with your problem! Let me know how it went.
Had a look at your test project you kindly added.
The problem is that the font you are setting is too big (100pt) and the 450 point height can not be satisfied. You have set label.adjustsFontSizeToFitWidth = true
which is causing it to try and fit it in as best it can by using a smaller font.
So when you set the font to 100, it is sizing the text area based on fitting the original text truncated and then it compresses it by changing the font to fit the width. This leaves a gap at the top and bottom after the compression as the size was based on the original font.
If you use smaller sizes like 90, it works fine as it fits in less than 450.
If you remove adjustsFontSizeToWith it works fine and fills the space, but it truncates the text.
If you remove the height constraint it works fine, but its height goes > 450.
So your problem is simply that the test font is too big for 450 height.
Ask the label for the font size needed using the answer from here: How to get UILabel (UITextView) auto adjusted font size?
Basically you use:
CGFloat actualFontSize;
[label.text sizeWithFont:label.font
minFontSize:label.minimumFontSize
actualFontSize:&actualFontSize
forWidth:label.bounds.size.width
lineBreakMode:label.lineBreakMode];
This is deprecated but that does not mean you cant use it for now. You need to convert it to swift.
Call this and if the font size is less than the original, set the font in the label the lower size. This in theory should give you a perfect fit as it should resize to the new font size you set.
I had a search for the swift equivalent of sizeWithFont
and there are many articles but none I could see which replaced the version of the function noted above.
A slightly inefficient solution would be to add the following before your addSubview
code in the test project you posted(excuse my swift). It basically searches backwards in font size until the font fits the known limits. This could obviously be made more efficient, but it shows that if you calculate the correct font before layout, then it will all fit perfectly at 450.0 height.
Tested this in your project and the text fits perfectly in the event of it originally not fitting at 450.0
// The current font size and name
var fontSize:CGFloat = 120
let fontName:String = "AvenirNext-Regular"
// The size to fit is the frame width with 60 margin each size and height
// of 450
let fitSize:CGSize = CGSize(width:view.frame.width-120.0,height:450)
var newSize:CGSize
do{
// Create the trial font
label.font = UIFont(name: fontName, size: fontSize)
// Calculate the size this would need based on the fitSize we want
newSize = label.sizeThatFits(fitSize)
// Make the font size smaller for next time around.
fontSize-=0.5
} while (newSize.height >= 450)
println("Font size had to be reduced to \(fontSize)")
view.addSubview(label)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With