Designing complex UI using Android ConstraintLayout

Souvik Biswas
ProAndroidDev
Published in
12 min readSep 16, 2020

--

Designing a complex user interface on Android having a nested view hierarchy was a common thing previously. But, with the introduction of ConstraintLayout, this has changed a lot. It reduces a lot of challenges of building complex layouts as now you can design them using the GUI of Layout Editor, by just dragging UI elements into a visual design editor instead of writing layout XML by hand.

You can take the full advantage of this Layout Editor while using ConstraintLayout (part of Android Jetpack libraries). It uses a flat view hierarchy and moreover it also provides some performance benefits.

If you want more information regarding the performance benefits of ConstraintLayout, check out this Android Developers Blog post.

Overview of constraints

You must set at least two constraints, one horizontal and one vertical constraint, to position a view element properly on the screen.

If you do not have Autoconnection turned on, any view that you drop in the Layout Editor stays where you leave it without any constraints. However, when you run an app with a view element without any constraints, it is by default rendered to the position [0,0] (the top-left corner of the device screen).

Now, let’s look into the different types of constraints that you can set on a view element.

Types of constraints

Android Studio allows you to use the following types of constraints:

  1. Fixed constraint: A constraint that is specified using a hard-coded number.
  2. Adaptable constraint: A constraint that defines a relationship in relative and weighted terms.
  3. Absolute positioning: A numerical positioning, such as the position in x, y coordinates.
  4. Relative positioning: Views are positioned by specifying relationships with other views.

Some of the useful features that you can use with ConstraintLayout are listed below:

  • Chains
  • Bias
  • Ratios
  • Guideline
  • Barrier
  • Baseline
  • Group
  • Circular positioning
  • Flow
  • ConstraintSet

Let’s talk about these in more detail.

Chains

A chain is a group of views that are linked to each other with bi-directional position constraints. The views within a chain can be distributed either vertically or horizontally.

Some of the ways in which chains can be styled are shown below:

  • Spread: Elements are evenly distributed along the mentioned axis. This the default style for chains.
  • Spread inside: Elements are spread to use the available space with the head and tail attached to the parent.
  • Weighted: Elements are resized to use all the available space according to specified weights with the head and tail glued to the parent.
    This can be achieved when the chain is set to either spread or spread inside. You can fill the remaining space by setting one or more views to match constraint (0dp).
  • Packed: Elements are packed to use minimum space.
  • Packed with bias: Elements are packed to use minimum space and are moved on their axis depending on bias.

The XML code with default chain style looks like below:

Bias

When a view is constrained to both sides on either axis, it is centered on that axis, and the bias value is set to 50%. You can adjust this bias by using the slider present in the Attributes panel under the Layout tab.

The XML code looks like below:

Ratio

In ConstraintLayout, you can set the size of a view by defining an aspect ratio. For using ratio, set at least one of the view dimensions (i.e., either height or width, or both) to match constraint(0dp).

Then you will notice a small triangle on the top-left corner.

Click on it to enable the ratio for that selected view. Now, you can define any aspect ratio in the format width:height (by default it is set to 1:1).

If you have the height fixed to a certain dp value or wrap_content and width to match constraint, then the ratio will define the width with respect to the height and vice versa.

If you have both the width and height set the match constraint, then the ratio will define both of them with respect to its parent. In this case, you get some more options, like if you press the triangle for the second time it will set the ratio with respect to the height (of the parent). Pressing the triangle for the third time will set the ratio with respect to the width (of the parent).

Applying ratio with only the width set to match constraint (0dp)

The XML code looks like below:

Guideline

A Guideline is a virtual helper object which allows you to create horizontal and vertical guidelines that are positioned relative to the ConstraintLayout container. You can then constrain other view elements relative to your specified guideline.

A guideline can be created by right-clicking on the Design editor, then under Helpers select either Add Vertical Guideline or Add Horizontal Guideline. You can also click the Guidelines icon in the toolbar to achieve the same.

After adding the guideline, you can drag the dotted line by holding the circle to reposition it (by default it is measured in dp from the left edge of the container).

You can click on the circle to toggle the edge from which the dp value is set or you can also set it in percentage.

The XML code looks like below:

Barrier

A Barrier is similar to a guideline, but unlike guidelines, it doesn’t need to have a fixed position. It can move based on the position of views contained by it, and you can constrain other view elements to it.

They are particularly useful when you’re laying out internationalized strings or displaying user-generated content whose size you cannot predict and can change during runtime.

You can create a barrier by right-clicking on the Design editor, then under Helpers select either Add Vertical Barrier or Add Horizontal Barrier. You can also click the Guidelines icon in the toolbar and select the option accordingly.

The XML code looks like below:

Baseline

You can align the baseline of multiple text views, regardless of their font sizes. This constraint makes it much easier to align text views.

If you are not sure what baseline is exactly, Material Design Typography states it as follows:

Material Design Typography

In order to create a baseline constraint, right-click on a text view and select Show Baseline. Then, you can just click on the text baseline of that view and drag it to the baseline of another to align them.

The XML code looks like below:

Group

You can use Group to logically group together certain view elements. A group contains references to the view ids. This is pretty useful if you want to change the visibility of multiple view elements, you just set the visibility of the whole group rather than setting for each element.

You can create a group by selecting the view elements, which you want to include in the group, then right-click and under Helpers select Add Group.

The XML code looks like below:

Circular positioning

Circular positioning allows you to constrain a widget center relative to another widget center, at an angle and a distance. This allows you to position a view element in a circular formation around the central view.

An example of a Floating Action Button with multiple options:

The XML code for this is as follows:

Flow

Flow is a part of ConstraintLayout 2.0 (it is currently in release candidate, the stable version will be announced soon). It allows you to lay out a long chain of view elements and wrap them into multiple rows or columns. You can specify the flow_wrapMode property to define the wrap style.

Following are the wrap modes available for Flow:

Wrap none: This simply creates a chain out of the referenced elements. It doesn’t try to fit them within the flow dimensions.

The XML code is as follows:

Wrap chain: This creates multiple rows or columns if the referenced views don’t fit within the specified dimension.

The XML code is as follows:

Wrap aligned: This is similar to the wrap chain style but will align the view elements along the row or column.

The XML code is as follows:

ConstraintSet

ConstraintSet allows you to create and save constraints defined using a ConstraintLayout. It also allows you to apply them to an existing ConstraintLayout. This can be used for creating animations very easily by defining a starting layout and final layout, and the rest is handled automatically by this class.

The following is a simple animation created using ConstraintSet:

First of all, you have to define the two ConstraintLayout, i.e the starting and the final layout.

Starting layout XML code:

Final layout XML code (with changed dimension of the Flow layout):

The Kotlin code for the animation is given below:

Now, let’s apply the concepts that you have learned above to build a sample app using ConstraintLayout with some simple animations.

Building an app using ConstraintLayout

We will be creating the following design of a movie ticket booking app:

The app will contain three layout designs which we will be creating using ConstraintLayout. Then we will use ConstraintSet to perform the animations while transitioning between these layouts.

Getting started

  • Create a new project using Android Studio.
  • Select Empty Activity and click Next.
  • Enter the name of the project and location. Select the language as Kotlin, and set the minimum SDK version to API 19. Click Finish.

This will create a new Android project for you. Wait for the build indexing to complete.

Main layout

The main layout will be consisting of a menu button (top-left corner), a cover image of the movie, and its description.

Start by placing the menu button by dragging an ImageButton from the Palette onto the Design Editor, and constraint it to the top-left corner of the layout with a margin of 16dp from the edges.

You can get the assets used in this project from my GitHub repository (the link is present at the end of this article).

Now, add two guidelines which will help in placing the cover image and other view elements on the screen. Place one at 15% and another at 85% from the left edge.

Add a TextView to show the movie status. Constrain it to the bottom of the menu button and to the left guideline.

Add an ImageView with the cover image. Constrain it to the guidelines that we added earlier and set the ratio to 2:3

We will use a vertical chain with style set to packed to constraint the all the description TextView.

The full XML code of the main layout is available here.

Now, we will add two more layouts which we will be using for transitioning to and fro.

Cover layout

The UI design of the cover layout is as follows:

This layout will contain the same elements as defined in the main layout. So, just copy-paste the XML code from the activity_main.xml file to the cover_view.xml file and then redefine some the constraints to achieve the desired UI.

The full XML code of the cover layout is available here.

Description layout

The description layout will look like this:

This layout is a bit complex, but can be easily achieved using ConstraintLayout.

First of all, copy-paste the same code from the activity_main.xml file to the description_view.xml file and modify the constraints as necessary. As you can see, this layout has some extra elements which has to be added.

The date selector can be created by chaining (horizontally) together the views containing date and day.

To center a view element vertically with respect to another, you can constrain the left and right side of the view to another.

The date view can be created by adding a simple view element with the background color set to white. The bar on top is also created in a similar manner, by adding a view with background color black. Then constrain the start and end of the view with respect of the start and end of the day text view.

Before moving on to the layout animations, you will need to define the position of the new view elements added in this layout in the other two layouts as well. As they should not be visible in those layouts, constrain them such that they are outside of the root view area.

NOTE: If you do not define the appropriate position of the new elements in the main layout, then they will not get loaded in other layouts as well.

The full XML code of the description layout is present here.

Adding animations

You can animate the transition between the layouts using ConstraintSet.

Following is the code for transitioning from the main layout to the cover layout:

If you see carefully, then you will notice that there is also a color transition of the texts and the icon buttons from black to white during this layout animation.

You can achieve the same, using this:

In order to animate the date selector, we will be modifying the constraints set on the date view element as a specific day/date is clicked.

  • Define a list of day TextView and a map of day to date TextView:
  • Set click listeners to these text views:
  • Define the method selectDate, and re-connect the constraints to the appropriate TextView as they are clicked on.

You have successfully completed building the sample ticket booking app.

Conclusion

ConstraintLayout makes it really simple to build complex UI designs in Android. And, ConstraintSet helps to animate between these layouts with minimum lines of code. There are a lot more functionalities to explore in ConstraintLayout. If you want to apply more complex animations, there is a subclass of ConstraintLayout called MotionLayout. This allows you to define a whole new level of animation to your Android apps.

Originally published on Codemagic Blog.

--

--

Mobile Developer (Android, iOS & Flutter) | Technical Writer (FlutterFlow) | IoT Enthusiast | Avid video game player