It seems impossible to get the UILabel to adhere to the constraints in the way that I want it to consistently. The leading and trailing space constraints seem in effect but the label is just truncating the lines instead of expanding to new lines.
I do have the numberOfLines of the UILabel set to 0. I have also tried the suggestion listed here: UILabel not wrapping text correctly sometimes (auto layout) and it didn't seem to work reliably. The last thing I tried was setting the setContentCompressionResistancePriority property to Fitted and Low but it doesn't work for everything in the UITableView at the same time. In fact, depending on if the tableview gets refreshed, it looks like all the wrapping can get undone.
The only thing that I tried that seemed to work well was to set the preferredMaxLayoutWidth of the UILabel to a constant. I was just hoping to use it as a last resort to avoid calculating how wide the label should be at runtime. Surely, there's an out of the box way to get what I want.
The key to getting it to work correctly was to ask the view to reset the layout after the constraints had been applied and all the text had been set. I merely added these lines to my custom UITableViewCell after I had set the data that it needed:
//set data
//set constraints
...
contentView.setNeedsLayout()
contentView.layoutIfNeeded()
}
I realized this was the solution because the view kept reporting their initial frame sizes instead of sizes after being affected by their constraints. For some reason, all the other views looked correct but not the UILabels.
I found the solution in the answer posted here: https://stackoverflow.com/a/13542580/1637033
You can calculate height of of the UILabel runtime as per the content
func heightForLabel(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
}
Related
I am getting a weird behaviour of UILabel in ScrollView. I am assigning dynamic text to the UILabel and using sizeToFit, I can log the new size which seems to change correctly after assigning text but I can't see the changed size reflected in both the simulator and the real device. This is the log before assigning and after assigning text
--txt Frame {{15, 325}, {291, 36}}
--txt Frame1 {{15, 296}, {291, 446.5}}
As you can see, the size (height) changes though I don't see the changes on device and simulator. Please help.
try to add this after sizeToFit()
self.view.setNeedsLayout()
self.view.layoutIfNeeded()
override func viewWillLayoutSubviews() {
self.myLabel.layoutIfNeeded()
}
Have you set the numberOfLines property for that label Before use the sizeToFit method.
may be that also cause the problem.
may be the label frame is change but label's numberOfLines property is set to 1 so it display only 1 line.
try to set the number of lines property before using sizeToFit method, like
label.numberOfLines = 0;
[label sizeToFit];
this will set the all the text for any number of line in label.
Hope it will Help you.
After experimenting with different approaches, I ended up manually extending the height of the contentView in IB myself. Its not the most elegant solution but it works for now :(
Ok, so I have simplified my problem down to its most basic form. I have a view whose width is 0.7 times its main view. I am programmatically adding a UILabel into that view and I am trying to make it the same size. I am then printing out the size into 2 views for debugging purposes.
Here is my code:
let test = trackerView.bounds.size.width
let testLabel = UILabel(frame: CGRectMake(0,0,test,30))
testLabel.backgroundColor = UIColor.blueColor()
trackerView.addSubview(testLabel)
lblStageDescription.text = testLabel.bounds.width.description
lblTime.text = trackerView.bounds.width.description
And this is what my simulator looks like
The blue is the TestLabel and that white part underneath of it is the trackerView.
Then the 2 numbers 420.0 are where the widths are printed out.
Is there something different about the sizing for a UILabel vs a UIView? Am I missing something? Any help would be appreciated.
Thanks!
What method is the code in? Are you using auto layout? What device are you testing on? If it's an iPhone, 420 points is wider than a view controller's view. Can only speculate that you've used auto layout and then added the view in viewdidload before constraints were applied. Causing trackerview to get resized. Try moving your code to viewdidappear or viewdidlayoutsubviews.
let testLabel = UILabel(frame: CGRectMake(0,0,test,30))
testLabel.backgroundColor = UIColor.blueColor()
trackerView.addSubview(testLabel)
This is the code that is creating the label. I'm not sure about the label you created in IB but this is a declaration with initializer, so your code is interacting with it and by default has no constraints. You can set trackerView.clipToBounds = true so it's subviews won't extend past it's bounds, but the label will be clipped as well.
I am making a app without using storyboard. The app has a long text so I can't get enought space on one line. The app is for both iPad and iPhone. The adjustSizeToFit = true does not work, is there a metode to adjust size of label with multiple lines?
There is no property on UILabel called adjustSizeToFit. Are you sure you didn't mean adjustsFontSizeToFitWidth? Which if you look at the documentation, says:
Normally, the label text is drawn with the font you specify in the font property. If this property is set to true, however, and the text in the text property exceeds the label’s bounding rectangle, the receiver starts reducing the font size until the string fits or the minimum font size is reached. In iOS 6 and earlier, this property is effective only when the numberOfLines property is set to 1.
Which I'm not sure is what you wanted.
If you wanted a UILabel with an arbitrary number of lines, where the text is contained within a certain width, continue reading:
What you do will depend on whether you're using AutoLayout or not:
Not AutoLayout
Just use:
let size = label.sizeThatFits(CGSize(width: myWidth, height: CGFloat.max))
// CGFloat.max, because we don't want to limit the UILabel's height.
label.frame.size = size
AutoLayout
Firstly, you should set numberOfLines to zero.
Secondly, you need to tell AutoLayout how long each line can be, this doesn't default to the width of the label. For this you need a UILabel subclass:
class myLabel : UILabel {
override func layoutSubviews() {
// 1. Get the label to set its frame correctly:
super.layoutSubviews()
// 2. Now the frame is set we can get the correct width
// and set it to the preferredMaxLayoutWidth.
self.preferredMaxLayoutWidth = self.frame.width
}
}
I am using UILabels with numberOfLines=0 and lineBreakMode = NSLineBreakByWordWrapping in a "dynamic" UITableViewCell . I utilize AutoLayout to attach the label to its container cell at the top, bottom, trailing and leading edges. In iOS7, the label's height updates dynamically with its content, however in iOS8 it truncates prematurely (usually at 1 line, but sometimes at 2). In iOS8, I have confirmed that the intrinsicContentSize of the label is dynamically updating as expected, but the label's frame is not following suit. Here is the difference seen between iOS7 and iOS8:
I have read of similar bugs in iOS8, but have been unable to implement a workaround. I have tried setting the label's text to #"" and back to #"Abraham Lincoln: Vampire Hunter" (as mentioned in this question), but that does not remedy the issue. Also notice that in iOS8, the cell size does increase according to the label's intrinsicContentSize, but for whatever reason, the height of the label itself does not. Any suggestions would be greatly appreciated. I would be glad to provide more information as well.
iOS 8
iOS 7
This is my walk around
subclass of UILabel, and override this function.
-(CGRect)textRectForBounds:(CGRect)bounds
limitedToNumberOfLines:(NSInteger)numberOfLines
{
CGRect rect = [super textRectForBounds:bounds
limitedToNumberOfLines:numberOfLines];
float height = rect.size.height;
int hightRound = (int)roundf(height);
rect.size.height = hightRound;
return rect;
}
Using autolayout I can't override my label in code. I've set the labels attributes in IB: Lines = 0, LineBreaks = Word Wrap, but I have my height set to a single line because due to what cell is selected determines what text goes in the label. So sometimes the label will only have one line.
In my viewDidLoad:
myLabel.text = #”blah, blah, blah….”;
[myLabel setLineBreakMode:NSLineBreakByWordWrapping];
myLabel.numberOfLines = 0; //have tried 1 but didn’t help
[myLabel sizeToFit];
This works on another project, but I wasn’t using AutoLayout. AutoLayout seems to override these settings.
I’ve even added
[myLabel setFrame:CGRectMake(20, 135, 280, 80);
but it doesn’t help.
Allow the intrinsic size of the label determine the height. You are correct that you need to set the numberOfLines property to 0. Since you are using AutoLayout, don't call sizeToFit and you need set the preferredMaxLayoutWidth of the label.
That's because your label's properties are set only once (in viewDidLoad), while the constraints from autolayout are applied everytime your view's layoutSubviews is called.
Also, using a line break mode that wraps the text won't work well with your UILabel if it's adjusting fonts, as per Apple's docs.
If this is a UIViewController, move the UILabel override code into - (void)viewDidLayoutSubviews, or if this is in a UIView, move the code to - (void)layoutSubviews.
Don't forget to call [super viewDidLayoutSubviews] or [super layoutSubviews] in those calls.
That being said, if you see yourself needing to override your constraints, either set up the constraints and properties to what you want in the nib file, otherwise use pure code to set up your label.
You need to set preferredMaxLayoutWidth to the maximum width your label can be. You should do this in viewWillLayoutSubviews.