Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to easily collapse vertical space around label when its text is nil?

Suppose I have three labels that are laid out below each other in a column. The uppermost label's top edge is pinned to the superview's top edge. All following labels' top edges are pinned to the preceding label's bottom edge. The leading and trailing edges of all labels are pinned to the leading and trailing edge of the superview. Here's what it looks like in Interface Builder (I added a blue background on every label to visualize its extent).

Screenshot showing labels in interface builder

In the simulator the result looks like this.

Simulator screenshot showing three labels

All labels are connected to outlets in a view controller.

@IBOutlet weak var label1: UILabel!
@IBOutlet weak var label2: UILabel!
@IBOutlet weak var label3: UILabel!

When I set the text of label2 to nil

label2.text = nil

the label itself collapses.

Simulator screenshot showing the collapsed middle label

However, the top and bottom spaces around the label do not collapse. This is evident by the fact that there is no blue background on the middle label in the last screenshot. As a result, the space between label1 and label3 is double the space of the layout in the first screenshot.

My question is - on iOS8 - what is the easiest way to collapse either the middle label's top or bottom space so that the two remaining labels still use the vertical spacing defined in the original layout? To be clear, this is the result I want to achieve.

Simulator screenshot showing reduced spacing between the two remaining labels

Options I've found so far:

Bottom/Top Spacing Constraint Outlet

Define an outlet for the middle label's top or bottom spacing constraint.

@IBOutlet weak var spacingConstraint: NSLayoutConstraint!

Store the constraint's initial constant into a variable (e.g. in awakeFromNib or viewDidLoad).

private var initialSpacing: CGFloat!

override func viewDidLoad() {
    initialSpacing = spacingConstraint.constant
    ...

Set the constraint's constant to zero whenever the text is set to nil or back to its initial value when the text is not nil.

spacingConstraint.constant = label2.text == nil ? 0 : initialSpacing

This approach feels a bit clumsy since it requires two additional variables.

Height Constraint Outlet

Set the vertical spacing around the middle label to zero and increase its height by the same amount. Define an outlet for the height constraint and proceed as above, setting the height to zero when the text is nil and back to it's initial value when the height is not nil.

This is still as clumsy as the previous approach. In addition, you have to hardcode the spacing and cannot use the built-in default spacings (blank fields in Interface builder).

UIStackView

This is not an option since UIStackView is only available on iOS 9 and above.

like image 659
hennes Avatar asked Sep 26 '22 18:09

hennes


1 Answers

I'm using this UIView category for this purpose.

It extends UIView by adding two more property named fd_collapsed and fd_collapsibleConstraints using objective-c runtime framework. You simply drag constraints that you want to be disabled when fd_collapsed property set to YES. Behind the scene, it captures the initial value of these constraints, then set to zero whenever fd_collapsed is YES. Reset to initial values when fd_collapsed is NO.

There is also another property called fd_autocollapsed

Not every view needs to add a width or height constraint, views like UILabel, UIImageView have their Intrinsic content size when they have content in it. For these views, we provide a Auto collapse property, when its content is gone, selected constraints will collapse automatically.

This property automatically sets fd_collapsed property to YES whenever specified view has content to display.

It's really simple to use. It's kinda shame that there is no builtin solution like that.

like image 123
limon Avatar answered Sep 30 '22 05:09

limon