Having worked on an app with both native iOS and Android versions, it’s been interesting to compare and contrast the layout approaches of both platforms. iOS has had a constraint-based layout system for quite some time now in the form of AutoLayout, while Android has only recently added a similar system called ConstraintLayout.
On my current project, we have been creating all layouts in code using Masonry. Our workflow has generally involved implementing on iOS first, then porting to Android. This means we need to take an iOS layout, specified as a system of constraints, and try to figure out what combination of RelativeLayout, LinearLayout, and FrameLayout will produce the same result.
I decided to give Android’s ConstraintLayout a whirl, and I couldn’t help drawing some comparisons to AutoLayout in a few key areas.
Hiding a view is easy, but reconfiguring constraints so that the view doesn’t leave an empty gap is a little trickier. On iOS, UIStackView helps to address this somewhat, although it’s still possible to end up with conflicting constraints. It also requires iOS 9, so it may not be an option if supporting earlier versions of iOS is important (we only recently dropped support for iOS 8).
Before comparing to Android, I should discuss a few of the approaches we’ve tried on iOS.
My first solution was to set up the constraints assuming all views were visible. Then I added some additional deactivated constraints to rearrange the layout when certain views were hidden. At runtime, I performed some surgery on the layout by activating those constraints and deactivating others. This approach was effective but very tedious to set up and maintain.
Another approach is to just crush the view in order to make it disappear (that is, add a new constraint that sets its height or width to zero). This works for some views, but trying to do it on anything with subviews is a sure way to cause conflicting constraints. It’s usually possible to get it to work by fiddling with constraint priorities, but again, it’s very tedious to set up and maintain.
It was a pleasant surpise to find that on Android, hiding a view is generally as simple as setting its visibility to GONE. In my experience, this has worked for all of the different sorts of layouts, including ConstraintLayout.
Visual Editor vs. Text Editor
Editing a layout visually, without having to build and run, is a huge time saver. But sometimes the visual editor just gets in the way, or it doesn’t render the same as the runtime environment. That’s why it’s useful to be able to edit the layout more precisely in text form.
Android Studio has long had this functionality, although I have typically preferred to create and edit layouts in XML. But with ConstraintLayout, I have found myself using the visual editor to quickly construct new layouts (editing constraints as long-winded attributes on an XML tag is not entirely pleasant).
With both Android Studio and Interface Builder, the effectiveness of the visual editor decreases rapidly as the complexity of the layout increases. Android Studio’s ConstraintLayout editor becomes a twisted mess of little arrows. And good luck deciphering the pile of constraints listed by Interface Builder. In this case, it’s often easier to jump to the textual representation, but for iOS that’s a no-go: you have to choose upfront whether to use Interface Builder or build your layout in code.
Number of Constraints
When I first started playing around with Android’s ConstraintLayout, I was disappointed to find that it felt very much like an incremental improvement to RelativeLayout. The biggest drawback was that a view can only have one constraint per edge, whereas on iOS, you can just keep adding as many constraints as you want.
But I think this limitation actually turns out to be a strength. Yes, it forces me to think a little harder about how my layout fits into Android’s rules, but it also eliminates a ton of AutoLayout rules that are impossible to keep straight (constraint priorities, content hugging, compression resistence, intrinsic size, etc).
I know I’ve spent my fair share of debugging layout issues on both platforms, so I can’t say for sure that one is definitively better than the other in this area.
It hardly seems important, but one thing that does baffle me about ConstraintLayout is the limited usefulness of the baseline constraint. (The baseline of one view can only be constrained to another baseline.) This is fine for aligning two text views, but what if I want to align the baseline of some text with the bottom of an image? ConstraintLayout is still pretty young, so I’m hoping this will be added eventually.
ConstraintLayout seems to be stretching the limits of XML as a layout language. It works, but it’s just a bit awkward at times. Even so, I actually like its overall simplicity, so I’m keeping my fingers crossed that it only gets better from here. It may not be perfect, but it certainly is a step in the right direction.