UITableView cell vertical centering of label when another is empty - ios

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.

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:

Horizontal UILabels inside a self sizing UITableViewCell

Question: How can I use constraints in a UITableViewCell using UITableViewAutomaticDimension when there are labels side by side which can each contain a different number of lines?
I have a table with cells that contain labels side by side:
I'm having a hard time getting the cell to size properly if one of the labels on one side have more lines than the corresponding label on the other side. One of the labels always gets cut off. If both labels have the same number of lines, the cell resizes perfectly and all text can be seen.
I've tried a number of constraint tweaks but nothing is working perfectly as desired.
I've tried adding hidden label for height...but it doesn't work well for the cell with 4 labels
I've tried placing the labels in a view but then the height of the view still needs to be calculated.
Currently the constraints are setup normally: top, bottom, left , right, labels are set to 0 lines etc and works great when both labels have the same text or same number of lines.
Is there any way I can do this with constraints? Or do I need to revert to the old height for row at index path? =(
There is a way to achieve what you want to do just using constraints. The trick is to set the relation of the constraints between the two lower labels and the bottom to Greater Than or Equal instead of equal.
Here is how I set the constraints:
Which has this result:
Or you could set the constraints between the labels top and bottom to Greater Than or Equal and leave the bottom constraint at equal:
To get this result:
I found a solution where I did not have to revert to using tableView:heightForRowAtIndexPath.
I added a label to the cell with the text color set to clearColor and called it 'heightLabel'. I added constraints to the heightLabel so the cell would resize based on the heightLabel's constraints.
Then whichever of the left or right labels had the most text, I placed that label's text inside the heightLabel.
The cells still were not resizing and I had to call 'layoutIfNeeded' on the cell before returning the cell in tableView:cellForRowAtIndexPath.
The heightLabel constraints are now what is being used to resize the cell and UITableViewAutomaticDimensions is working properly.
This may not be the best solution but it's working out pretty well. If there is a more proper way of doing this I'm open to suggestions.

same space retain between three label using autolayot

I am learning auto layout from last two days, i have one UITableViewCell xib file and in this cell there is two Labels and one Button, How can i manage Horizontally and vertically space between this subviews of cell?
Thanks in advance.
This trick is to add empty placeholder UIViews between your labels/buttons and bind them with an Equal Width constraint.
Following images show how it is done for horizontal spacing. Purple colored views are the placeholder UIViews. You can later set their alpha=0 or make them hidden so they will not appear when the app is running.

Custom/Dynamic label width using auto layout

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.

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