Targetting iOS 8.1
I am using AutoLayout to lay out a number of Labels in a TableCell. Some of those Labels are optional and some can wrap their Text. They are split across two "Columns", these columns are simply two UIViews in the TableCell's ContentView. My constraints are applied programatically.
SECOND UPDATE
Without SwiftArchitect's answer below I would not have solved this and have accepted his answer. However because mine is all in code, in a custom tablecell, I have also added a separate answer below
UPDATE
In an attempt to stop the labels from stretching to a size larger than they needed to be I had previously set the SetContentHuggingPriority
and SetContentCompressionResistancePriority
to 1000 as I belived this was the equivalent of saying "I want the Label to hug its content to its exact height and I do not want it to ever be compressed vertically"
This request was clearly not being complied with by AutoLayout as you can see in the Red and Pink examples below.
this.notesLabel.SetContentHuggingPriority(1000, UILayoutConstraintAxis.Vertical);
this.notesLabel.SetContentCompressionResistancePriority(1000, UILayoutConstraintAxis.Vertical);
I removed the setting of these priorities and the labels are no longer being squashed which was my original issue. Of course now certain labels are stretched beyond the height they need to be.
Here are a couple of screenshots of what it did look like when the Compression and Hugging priorities where set. The background colours are for debugging
The general problem was that the Containing View's (colored purple and red) were sizing themselves to the smaller of the two. As you can see in the top one "Priority 3" is being cut because the left column container doesn't need to be any higher.
In this next example there is no Priority label but the EventDate is being squashed.
'Fill proportionally' distribution type works with intrinsic content size. So if our vertical stack(height say 600) view has 2 views, ViewA (intrinsic content height 200) and ViewB(intrinsic content height 100), the stack view will size them to ViewA(height 400) and ViewB(height 200).
Auto Layout defines margins for each view. These margins describe the preferred spacing between the edge of the view and its subviews. You can access the view's margins using either the layoutMargins or layoutMarginsGuide property. The layoutMargins property lets you get and set the margins as a UIEdgeInsets structure.
The stack view aligns the first and last arranged view with its edges along the stack's axis. In a horizontal stack, this means the first arranged view's leading edge is pinned to the stack's leading edge, and the last arranged view's trailing edge is pinned to the stack's trailing edge.
The following answer has been written and tested. It works properly on iPhone & iPad, portrait & landscape. The tallest column wins, and the other one just takes the space it needs. It can even be modified to vertically center objects if need be. It addresses the vertically clipped label concerns, as well as dynamic scaling.
Preliminary advice
Storyboard
if you can. You can test all your constraints visually with a state-of-the-art GUI.UILabel
height: let each label take the space it needs vertically, and only add top and side anchorsmultiplier
to get, say 2 thirds and 1 third. Solution Description
For simplicity, I have created 2 subviews, 1 for each column, and positioned them side by side. They are anchored on top/left and top/right, their width is calculated, and their height is derived from their respective content(*).
The left and right subviews have a 1/2 multiplier
, to which I added a constant
of 2 pixels for margin. The labels inside these two columns are anchored left and right (leading space
to container and trailing space
to container), with an 8 pixels margin. This ensure no label ever bleeds beyond its column.
UITableViewCell
is the largest of the 2 inner columns. In other words, containerView.height >= left.height and containerView.height >= right.height.view.hidden
will not disrupt your constraints, and that is what you want.UILabel
left and right to container, the uppermost to the container as well, but every subsequent label.top should be anchored to the .bottom
of one above it. This way, your content will flow. You can add margins if you want.(*) The final key is to tie the height of each column with a constraint on the column to equal the .bottom
of the lowest label for that column. In the example above, you can clearly see that the right column, with a blue background, is shorter than the left one.
While I see you wanted a solution in code, I created my example using a Storyboard
in less than 15 minutes. It is not merely a concept, it is an actual implementation. It has exactly 0 lines of code, and works on all iOS devices. Incidentally, it has also 0 bugs.
List of All Constraints
Notice the >= sprinkled here and there. They are the key to making your columns independently tall.
The NSLayoutContraint
are virtually identical for L and R.
Get the Storyboard here, and a detailed article there.
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