ConstraintLayout in practice

Marko Ilicic
Undabot
Published in
7 min readMar 31, 2017

When creating complex and flexible views we need to combine and nest multiple layouts within each other, which often leads to performance issues on lower-end devices, especially when a complex view is used as a list item.

Android recently released the ConstraintLayout1.0.2 version and within Android Studio 2.3, the ConstraintLayout is used as the default layout in view templates. It should help us create more efficient and flat, but still flexible layouts.

Let’s create a happy little view using “old” layouts

1. View look and content variations example

On the left, we have a complex view which can have multiple states, and the views are positioned differently depending on the visibility of other views. Its components are very common and I believe that we’ve all received similar design requirements from our clients and/or designers.

With this kind of view, it’s impossible to achieve a flat hierarchy and keep the flexibility, even with the RelativeLayout. In this case, we need to combine multiple layouts with nesting to achieve the desired behaviour.

To achieve this behaviour without using a ConstraintLayout we need to create a hierarchy that looks like this:

Hierarchy of normal layout
2. Design and blueprint in Android studio with layout borders — normal view

You can see I used a lot of LinearLayouts since I needed to handle cases where other views should take the place of invisible views and everything should wrap evenly. LinearLayout weights are really useful :). Since we all know how to create a similar view, I won’t delve deeper into explaining this, and you can always check the source code.

Writing XML vs Design mode

When I started developing on Android, I wanted to create XML layouts, I mostly used Design mode since it looked easier than writing. But, very soon I realised that writing XML is not as hard as it seemed and I have switched to writing solely in XML. It’s a lot faster and you have a better control on placing views — at least from my experience. New versions of Android Studio added a lot of interesting new features; Design mode brought a lot of good things and I’ve often heard that we should give it a try. I’ve tried using it while building a view with a ConstraintLayout. While it really is good, especially for learning how constraints are created and what happens to the views, I still prefer writing XML than Design mode because Android Studio adds some extra properties which make code less readable and noisy. I’ve found it handy when I use it side-by-side since you can interact with the design and blueprint while writing XML. It’s also very useful when you want to check how the view will react to different constraints.

It’s time to create some constraints

So, let’s see how my view and hierarchy look after being converted to a ConstraintLayout:

XML for the view created with the ConstraintLayout (excluded irrelevant properties)

Well, this looks a lot better now, don’t you think? (except for the LinearLayout, but we’ll get back to it later).

Just to mention, Android Studio provides the option for converting existing views to ConstraintLayout, but it didn’t really work for me. Maybe it’s ok for simple layouts and maybe it will work better in the future, but I didn’t find it very useful at this moment.

3. Design and blueprint of a view created with the ConstraintLayout

On the 3rd image you can see how our view looks cleaner in contrast to the 2nd image while everything remained in its place.

You may have noticed that I’m not using AspectRatioImageView anymore. That’s because every child in the ConstraintLayout is able to define aspect ratio with the property, e.g:

app:layout_constraintDimensionRatio=”5:2"

Which I find very useful, especially for images.

All properties that are specific to ConstraintLayoutstart with a app:layout_constraint. At first it might look like there are too many of them; and that it’s too complicated for use, but they are really straightforward; e.g. if you want to align a top of the view to a bottom of an another view, simply use the layout_constraintTop_toBottomOf.

4. FAB constraints

Also, I didn’t need a helper View to centre FAB to the bottom-right of the image. If you want to centre a certain view to the other view’s side, make constraints from two sides of the view towards the one side of the other view. In my case I have used:

app:layout_constraintBottom_toBottomOf=”@+id/image”app:layout_constraintTop_toBottomOf=”@+id/image”

And how do we define a view size? Does it work like it does in any other view? Well, we can use a fixed size and wrap_content like with any other view, but we can’t use match_parent any more. I mean, you can try, but Android studio will instantly change that value to some fixed size which it thinks is good; and there is no arguing with him :). Instead, you should use match constraints, aka any size, which is defined by setting the height or/and width to zero dp.

I mentioned that I like weights in the LinearLayout, especially when I need to align multiple views which are prone to visibility changes (I’ve used this a lot in the example). Well, in the ConstraintLayout you can align those views directly without nesting. When a view’s visibility is set to GONE, it actually doesn’t disappear from the layout like in similar layouts.

Instead, it’s dimensions are set to 0 and the constraints are not lost, so all views which are linked with it will still be in the right place and this makes a UI very responsive. In this case we can also set a specific margin which will be used, e.g:

app:layout_goneMarginTop=”20dp”

Just to mention, all constraints also support start and end attributes for the RTL support.

As you can see on the 5th picture, I couldn’t make it fully flat, and that’s why I’ve added an additional nesting within the LinearLayout. Buttons are placed below two texts, and the top can be constrained only to the bottom of one of them.

Let’s say that the buttons are constrained to the description. If the description view has a smaller height than the comments view, the buttons would overlap it, so I had to put them in a new layout which is used for the top constraint of the buttons. Hopefully, we’ll get a solution for these situations in the future and if you already have one, please leave a comment. :)

6. Chained buttons

And lastly, the buttons are nicely packed and centred on the bottom of the view. By making a bi-directional connection between views, we create a chain within the views and it can have one of four styles. I’ve used "packed” since they need to be placed in the middle and side by side. If you need some other kind of behaviour, there is also a "spread" and "spread_inside". With a combination of 0dp on the height or width, it will behave like weights in the LinearLayout, and then we achieve the fourth style. Chain can be vertical or horizontal and their style is set to a “head view” (very top one on a vertical, and a very left one on the horizontal chain) with the:

app:layout_constraintHorizontal_chainStyle=”packed

There are some other features like bias and guidelines, although there was no need to use them in this example, they could be very helpful in many cases.

What about performance?

We all know that perf matters and we should always make well optimised views. Nested and complex views can create performance issues. Obviously, ConstraintLayout helps with creating flatter views, but how does it affect performance?

First of, let’s see how view and it’s children are measured on both views.

Measure passes for the normal layout

We can see that only buttons aren’t measured twice in the “normal” layout. RelativeLayout always has two passes while LinearLayout will make two passes if we use weight, and that’s the case with the first two LinearLayouts.

Measure passes for the ConstraintLayout

In ConstraintLayout some views are measured twice and some only once. That’s because it only measures twice the children whose dimension depend on the constraints which could affect the final height or width of the view. When you set the widthor height to wrap_content or to a fixed size, that view will be measured once and that could improve performance. In case you’ve used match constraints, that view will be measured twice.

7. Speed comparison in milliseconds between views

I wanted to see some numbers, so I tracked the time between the start of onMeasure() method and the end of onDraw(). Average speed improvement was around 9% in favour to ConstraintLayout. Average time for LinearLayout was 76 ms, and for ConstraintLayout 69 ms. The device used was Samsung Galaxy S4 mini with KitKat.

Obviously, the results will depend on the complexity of the view, but ConstraintLayout should generally give better results.

Conclusion

The ConstraintLayout is great for making flexible and responsive views in Android without having a deep hierarchy and it’s a real step up from the RelativeLayout. You should be able to make more efficient views already and we can only expect that it will get better over time. If you still have performance issues with complex views, and ConstraintLayout doesn’t solve it, I found creating a custom ViewGroup is still the best way to make a fast and fluid UI, but it can also be time consuming.

So go, play and experiment with it, if you already haven’t. :)

Thanks to Sinisa Cvahte for the design.

Thank you for reading. Please comment, like or share it with your friends and we hope to see you soon.

Would you like to join us? Check out the open positions at our Careers page.

--

--