mjl blog
March 1st 2016

Hiding UIView's in iOS

Standard UI widgets in iOS look quite nice. It’s what most non-game apps use. UI programming has never been one of my strong suits. But writing UI’s for iOS has always seemed one step too low-level. Note: I’ve also done Android programming, with UI’s, and it also doesn’t feel quite right. I can only imagine how painful writing big UI desktop programs must be. But I digress.

This post is about programmatically hiding UIView’s in iOS. UIView’s are generic containers of other UI interface elements (“widget” doesn’t seem to be the right word). Consider an app with a screen that lists details of an object. In my case the object was a hiking route. Some details might not always be set for a particular object. In my case the field describing the creator of the hiking route. You want to display that info if it was set. If not, show nothing. You could create the entire screen programmatically, and just leave out some UI interface elements. Programmatically creating the entire UI feels like one step too low-level though. I’ve used the UI interface builder that comes with xcode. With it, I added a UILabel that is the header for the creator-section, and a UILabel for the contents.

Now how do you hide these fields, depending on the hiking route that is being loaded?

One approach is to just set the “hidden” fields on the UILabels. That works, they will become invisible. But they will still take up space. This makes your UI have white holes in it. Definitely not the best solution.

An easy approach I’ve now taken is to put the UILabel’s in a UIView. Lay out that UIView so that it has zero vertical spacing with the UI elements above and below it. Lay out the UILabels such that they have a leading and trailing vertical spacing constraint to this containing UIView that is visually pleasing.

Now the trick is to use height constraints properly. I add a height constraint with constant 0 on the UIView, but with priority 1. This is a very low priority, so never takes precedence when autolayout is rendering the UI. The vertical spacing constraints on the UILabels (among themselves and to the containing UIView) must get a priority somewhat lower than the default priority 1000 (meaning “constraint must be satisfied or you’ve got an error in your layout”), say 900.

You can now “hide” the entire UIView by setting the priority to your UIView-height-constraint to 1000. This ensures autolayout will enforce that constraint. The other vertical spacing constraints will not be satisfied. Since they are below the mandatory priority 1000, their constraint won’t be satisfied, and that’s no problem. The result is that the UIView will be of zero height. Otherwise known as hidden, without taking up any whitespace.

You can display the entire UIView again by setting the priority of the height constraint back to 1.

You would expect there to be a simpler way to do this, but I haven’t found it. This is a recurring feeling with iOS development. Or maybe with mobile development in general: Android gives me the same feeling. This is probably just the way it is…