Custom/Dynamic label width using auto layout - ios

I have a table cell on which I presently have a UILabel say labelA whose height is dynamic i.e. based on the content. The label width is 290px. I wish to add another label next to labelA whose name is say labelB. The table cell and labelA looks as per below:
Question 1 - Here the height is expanding and I have 2 rows to display the entire text here. But it looks like width for the 1st and 2nd row is same as 290. Is there a way I can stop the width of the label where my text ends i.e. in this case the width of my label for 1st row should be 290 but for 2nd row it should end after the last work "Paul" so that I can start my next label labelB from there?
Question 2 - Also, while creating the xib, I am placing both my labels on the same row. If I set a constraint between both the labels, can labelA push labelB down to another row when it expands?
My cell and labels finally should look as below where the label with purple background is labelA and rect with orange border and white solid color inside is labelB.
Please let me know if this is possible? I am still a noob in iOS and auto layout.

To answer Question 1, UILabel will always draw text into a rectangular frame. You can't have one UILabel draw two lines of text the way you're looking for. You could use two UILabels, one for each line, but you'd have to do some manual calculations to figure out how much text will fit in the first label, and then what text to "overflow" to the second (boundingRectWithSize:options:attributes:context: would be your friend for this).
To answer Question 2, you should pin the bottom edge of labelB to the bottom edge of labelA. Let the height of each label be determined by the intrinsic content size. Assuming the font is the same, this should result in the result you want. (You can also try aligning the two labels' baselines, but I can't recall how that behaves for multiline labels.)
By the way, you should look into iOS 7's Text Kit. I personally haven't had a chance to dive into it in much depth yet, but it's very powerful and you might find a better way to do what you're after here.

Related

UITableViewCell expanding animation with self-sizing labels, visual animation problem

I've got a problem with self-sizing and animatable table view cells, with the animation part only.
The issue is that when the cell expands, 2 of the labels are overlapped as the other items expand. If you look at the gif below, the top label "370 Base Axle Ratio" becomes overlapped by the middle elements. Those middle elements slide down as a group, which is also undesirable, and if you look closely, the "0" under the words in the middle "Original Production" is also overlapped and it expands or is revealed incorrectly.
The top bold label "370 Base Axle", is set to be 0 lines of text so it can expand to fit multiple lines. The center group of labels is anchored to the bottom of that label. The bottom long text label is anchored to the bottom of the middle "0" label.
If I anchor the middle group of items to the top of the view at a fixed amount, then the expansion works without the overlap effect, but of course this breaks the dynamic nature of having multiple lines of text in that top label.
This layout is built with auto-layout, but is not using stack views (and is not my preferred solution at this time).
No specific code is used to set any layout sizes, only using this in the tableViewController after I add or remove the text in the bottom label:
tableView.beginUpdates()
tableView.endUpdates()
How would I fix this so the ONLY element that would expand is the bottom most label with the long amount of text, but still have a variable label height at the top?
TL;DR: Labels with multiple lines of text breaks animation when other multi-line labels are animated in a "show more" style of expanding table cell.
You can almost fix your issues with very few changes.
Two important things:
For all labels, set both Hugging and Compression Resistance to 1000 (Required)
Make sure you have a complete vertical constraint chain.
Couple drawbacks to your method of setting / clearing the text of the label though. The expand animation will work well, but the collapse animation will look as it does in your original gif --- the text disappears instead of being covered. Also, you have extra spacing at the bottom.
To get around that, you can set a constraint from the bottom of the "description" label - as you likely have it now - to the bottom of the content view... this will be the "expanded" constraint, AND add another constraint from the bottom of the "center 0" label to the bottom of the content view... this will be the "collapsed" constraint.
Those constraints will conflict at first... so change the Priority of the one of those constraints (doesn't matter which) to 750 (Default High) and the other constraint to 250 (Default Low).
When your app is running, you would swap the priorities based on whether you want the cell expanded or collapsed.
I put together a sample app using your layout - You can download it here: https://github.com/DonMag/Maverick
I use background colors to make it easy to see the frames. There is a line in cellForRowAt that can be un-commented to clear the colors.
The result using your set / clear text approach:
and using the Constraints method:

Chat TableView Cell: A UIView, whose size should depend on the larger containing label

I want to make a chat table cell, with content label and a time label.
Requirements are:
The blue UIView's size (width) should depend on the wider label within it.
The UIView should leave at least 61 dpi to the right of the cell.
The label should be able to wrap the text inlined in it.
This is the structure:
Thanks for your help!
Give the label constraints that go to the edges of its superview according to what you want
Set constraints on the view so that its size is not restricted to a specific height, e.g. use a combination of constraints with lower priorities and inequality constraints (i.e. greater or less than or equal to). Not entirely sure what your goal is so I can't really be more specific.
Set the number of lines of the label to 0

UITableView cell vertical centering of label when another is empty

I have a UITableViewCell that contains two labels positioned vertically one on top of another, and I am using AutoLayout.
The cell works (and looks) fine when both labels have some text.
Sometimes, though, the top label does not contain any text, and in this case I would the cell to have the same height, but the bottom label to be centered vertically. Is it possible to do it with AutoLayout without modifying the constraints at run time?
I don't believe this can be accomplished without modifying something at run time. I see a few options if you'd like to do this without changing constraints programmatically, some messier than others:
First option, you could set three labels in the cell. Two labels that are stacked vertically and one that covers the whole cell vertically, fully overlapping both other labels. At runtime you can determine if the bottom label shouldn't contain text and then set the overlapping top label with the text you would have previously set on the top vertically stacked label.
Second option, you could utilize a label that has the height of both labels you currently have. Set this new (2x height) label to allow for 2 lines (can be done in InterfaceBuilder side options). Then at runtime interpolate the label.text attribute with both label's text. Put a new line character in between the labels if the second label has text. It would look something like this
In Swift:
my2xLabel.text = "\(firstLabelString) \n \(secondLabelString)"
In Obj-C:
my2xLabel.text = [NSString stringWithFormat:#"%# \n %#", firstLabelString, secondLabelString];
All of this being said, modifying the constraints at runtime may be a less hacky way to achieve this formatting.
Make two prototype cells then. One will be the one you have right now, the other would contain only one label but centred vertically. Check if the text would be empty, return the cell with the vertically centred label. Otherwise, return the other cell.

UILabel that has unnecessary padding in a cell

I'm trying to make a Facebook clone for practicing iOS and I can't see why a label I have on my news feed gets unnecessary padding.
It only occurs on some labels, others on my news feed turn out fine. However for a select few there's a block of white pace above and below. At first I thought it was an alignment issue so I changed the labels background to green to show that the constraints hold out.
Anyone know as to why it's placing the padding, only for a select few?
By default UILabel will center its content vertically. Therefore, if label.bounds.size.height is greater than size of the text, the label's instinct is to center the content vertically, which will results in the vertical padding that you see in the attached image. Ensure that the label's height is being set according to the height of the text it contains and the problem should go away.
As dbart pointed out your label's frame is likely higher than the text needed. You can fix this by calling -sizeToFit. You can also check the amount of space the label is actually using for text by using +textRectWithBounds:maximumNumberOfLines:
If your cell is using autolayout to determine the height of the label you should set the preferredmaxlayoutwidth to an appropriate value (for example table width) before laying out the cell.

UILabel alignment to other UILabels

I have a cell prototype that i'm trying to add two labels to. I have the two labels right next to each other, but the size of the labels are dynamic, so I want the second label to be able to shift depending on the size of the first label.
Basically, I want there to be a fixed gap between the two labels, but the two labels' sizes are dynamic.
How do I do that?
EDIT:
Actually I found out how to do it via Storyboard. If you select the two labels you want to have a fixed gap between, just command select both of them and then go to the corner of storyboard and click the pin menu, which is that little 'H' looking thing in the group of buttons near zoom in/zoom out in the bottom right corner of the storyboard screen.
Get the label size by this method:
- (CGSize)sizeWithFont:(UIFont *)font
https://developer.apple.com/library/ios/#documentation/UIKit/Reference/NSString_UIKit_Additions/Reference/Reference.html.
Then set label's textAlignment to NSTextAlignmentLeft and NSTextAlignmentRight, and set frames by the string size and other offset.
UIView -sizeThatFits: and -sizeToFit will allow you to manually calculate a position for the second label. This is slightly more accurate than using the NSString method, as there's more to a UILabel than just the text — this will respect content insets, etc.

Resources