Blog

We believe there is something unique at every business that will ignite the fuse of innovation.

What is Constraint Layout?

Constraint Layout ("CL") is the latest addition to Android’s collection of layouts. Constraint Layout is a layout that will feel very similar to RelativeLayout at first glance, but as we will see in this article, CL is more powerful and versatile. CL aims to make developing layouts easier, faster, and more intuitive, while improving performance at runtime. If you are interested in speeding up your development time, this article will illustrate many of the basic features of CL, as well as the updated Layout Editor ("LE").

Why do we need Constraint Layout?

Speed!!! In many ways, the development of CL and the new LE are all about speed. One of the benefits of CL is its ability to help developers avoid the need to nest ViewGroups, in particular, weighted LinearLayouts and RelativeLayouts. The reason to avoid nesting is because the rendering time can grow exponentially with each level of nesting. If the layout time grows too large, your app will start dropping frames; resulting in choppy transitions.

Second, CL is being built from the ground up alongside the new LE. This means the Google Tools developers have taken the time to ensure that layout development with CL and LE is as intuitive and efficient as possible.

How do I get Constraint Layout?

To get started with CL, you will have to ensure you are pulling in the CL library. Luckily, Google is making this a standalone library; meaning updates should be on a regular cadence. Add the following line into your app/build.gradle:


    dependencies {
        compile 'com.android.support.constraint:constraint-layout:1.0.0-alpha4'
        // other dependencies
    }

At the time of writing this blog, 1.0.0-alpha4 is the latest version of CL available. Please note your version could be different.

In addition to pulling in the latest CL library, you will also need the updated LE in your Android Studio ("AS") install. At the time of writing this article, the LE is only available on the Canary channel (more specifically, Android Studio 2.2 Preview 7). If the design tab of your layouts look like the image below, you have the proper version of Android Studio installed.

Blank layout editor

If your LE does not look like the image above, check out this link for instructions on how to switch to the Canary channel or even install a Canary channel version side by side with your Stable install.

How Does Constraint Layout Work

One of the main goals of CL is to give developers a way to efficiently create complex layouts with minimal (ideally, zero) nesting (aside from what is directly inside of a CL). It is best to see how this is achieved by reviewing a few of the available properties in the xml for a widget that is placed inside of a CL. There is a basic pattern to follow when trying to understand these properties. An example pattern is below:

app:layout_constrainThisPartOfMyWidget_toThisPartOfAnotherWidget="@+id/another_widget"

So, with this pattern in mind, let's look at a few examples and see how CL achieves the flexibility needed to maintain a flat layout hierarchy. In the xml snippet below, you can see a TextView with ID, myTextView. myTextView is essentially centered in the activity_main layout. Its bottom is constrained to the bottom of activity_main, its left is constrained to the left of activity_main, etc. Also, its vertical and horizontal bias default to 0.50 (more on bias later). You can also see otherTextView is constrained to activity_main and myTextView. This is the real core of how CL maintains that zero-depth layout; by allowing widgets to be constrained to their peers and the parent layout in nearly any imaginable way.

<TextView
    android:id="@+id/myTextView"
    ...
    app:layout_constraintBottom_toBottomOf="@+id/activity_main"
    app:layout_constraintLeft_toLeftOf="@+id/activity_main"
    app:layout_constraintRight_toRightOf="@+id/activity_main"
    app:layout_constraintTop_toTopOf="@+id/activity_main"/>

<TextView
    android:id="@+id/otherTextView"
    ...
    app:layout_constraintBottom_toTopOf="@+id/myTextView"
    app:layout_constraintLeft_toLeftOf="@+id/activity_main"
    app:layout_constraintRight_toRightOf="@+id/activity_main"
    app:layout_constraintTop_toTopOf="@+id/activity_main"/> 

The example above shows only a small sample of possible constraints. The list of possible constraints includes the following (as well as many others).

<View
    app:layout_constraintBaseline_creator="@+id/some_view"
    app:layout_constraintBaseline_toBaselineOf="@+id/some_view"
    app:layout_constraintCenterX_toCenterX="@+id/some_view"
    app:layout_constraintDimensionRatio="@+id/some_view"
    app:layout_constraintEnd_toEndOf="@+id/some_view"
    app:layout_constraintGuide_begin="@+id/some_view"
    app:layout_constraintGuid_Percent="@+id/some_view"
    app:layout_constraintHorizontal_bias="@+id/some_view"/>

If you would like to create your layouts exclusively with xml, that is achievable; however, the Google Tools team kept CL in mind while developing the LE, thus it is easy to drag, drop, and fine tune your layout and constraints right from the LE user interface. Let's review that further.

Layout Editor Features

There are several differences between the old layout tool and the updated LE. Let's review those differences one by one to ensure a strong understanding of enhanced functionality.

Design View and Blueprint View

The first thing that jumps out with the new LE is the two 'layout previews' in the main portion of the editor. The preview on the left is called the Design View and should look rather familiar. For the most part, this is the same design view we had in previous versions of AS. The noticeable difference between the new Design View and the previous version is that it displays constraints when your mouse is hovering over the Design View.

On the right is the Blueprint View. This view shows the widgets in your layout and their size, position, and how they are constrained to other peer views and/or the parent layout.

Design View and Blueprint View

Let's take a close look at a single element within the Blueprint View. When a widget within the Blueprint View is clicked, several elements are displayed on top of that widget. Each corner has a 'resize' handle that can be used to resize the widget. Each side has an 'anchor point' that can be used to constrain the widget to something else. Finally, the rounded rectangle within bottom portion of the widget is another type of anchor point that can be used to align widgets according to their texts. 

Blueprint View Elements

Properties View

The Properties View is another aspect new to first time users of the updated LE. There is a fair amount of information packed into this view, but luckily, most of this is familiar to android developers, just displayed in a slightly different manner.

Properties View

At the very top of this view is where you can enter the ID of the particular widget currently highlighted. Below that is the the most interesting part of the Properties View. Let's start at the center of this section and work our way out.

First, the square directly in the center has several set of carats, pointing towards the center. These carats are one of three different sets of shapes that you'll see here. Each of the three different sets of shapes represent a different sizing method for the layout_width and layout_height. The inward pointing carats represent wrap_content. The 'I' shape represents a fixed value. Finally, the sawtooth shape represents a sizing method called any_size. any_size will be reviewed more later, but as a preview, any_size is similar to match_parent just with some tweaks in functionality to make it more intuitive and usable with CL. The sizing method can be changed by clicking on the shapes within the square or by the layout_width and layout_height dropdown menus.

Change Sizing Method

The 'T's that are reaching out of each side of that center square have a number close to the neck of each of them. This number represents the margins of the particular view or widget that is currently selected. So, if you wanted to modify the margin on any of the sides of a view, you can click on the number for said side and it will turn in to a dropdown menu where you can choose from common margin sizes or type in a custom size.

Quick Tip: If you have a view requiring a particular size margin on all sides, you can choose a default margin in the CL toolbar before you pull in the view. Then, when you pull in that view, any constraints you manually create (meaning, you didn't use 'Infer Constraints' or 'AutoConnect'...more on those concepts later) will have the default margin value selected in the toolbar.

Default Margins

The sliders along the left and bottom sides of this area within the Properties View are used to adjust bias. Bias is a new concept of android layouts that essentially replaces the capabilities of weighted linear layouts. You can think of the bias number as representing the strength of a spring that is pulling the currently selected widget to the top or the right of the layout.

  Bias

Notice that the bias reaches up to (not beyond) margins when calculating layout position.

Below the previously discussed area of the Properties View is where some of the more commonly configured properties are displayed and available for modification. For example, the text view has a small section where it can modify the text, content description, and text appearance.

More Common Properties

The 'text' property with the wrench symbol next to it is the text property in the tools namespace. This is used for previewing what text would look like in your layout while in the LE. The text field without the wrench symbol is what will actually be displayed in your app at runtime.

ArrowsFinally, if there are any other properties you'd like to modify for a given widget and you do not see it in the Properties View, you can click on the sideways arrows at the top of the Properties View or the link at the bottom, "View all properties", to see all possible properties configurable for the currently selected widget.

Guidelines

Guidelines will be a familiar concept to those who have used other design tools. A Guideline is a design-only tool which allows the developer to anchor widgets how they want; however, the Guideline will never be shown to the app user. It is used purely for design and layout purposes. Let's look at a quick example.

The Guidelines can be added directly to the xml, just like any other View, but to add it through the LE, click on the Guideline button in the CL toolbar and choose vertical or horizontal. After the Guideline appears on the layout, drag it to the desired position. Notice by clicking on the circular button at the end of the Guideline, it changes how the position is displayed. When clicked, the displayed position will cycle through distance from start, distance from end, and percent from start.

Guideline Cycling

Let's Build Something!

You can now utilize these foundational concepts to create your first layout using CL. Let's start by adding a main image at the top of the layout. Drag and drop an ImageView onto your Blueprint View. To add a constraint to any widget, simply grab one of the anchor points on a side of the widget and drag it to the target constraint point. When a constraint point is approaching, the LE will move the view to where it would be positioned if the constraint point was selected. If you are not happy with the preview, simply do not let go of the anchor point and choose another constraint point. If you like what you see in the preview, let go of the anchor point and the constraint will be created.

  Create Constraint

Modify the ImageView's properties in the Properties View such that it stretches to the left, right, and top edges. A quick way to stretch the ImageView from left edge to right edge is to set the layout_width parameter to any_size by clicking on the shape sets within the Properties View square until it shows a sawtooth shape or by setting the layout_width parameter to "0dp" in the dropdown menu. In this scenario, because there is no other view inline with our ImageView horizontally, any_size acts just like match_parent. Later in this demo layout, we'll see how any_size can cause a widget to layout differently if it does have a peer widget interfering with its layout. So far, we have something that looks like the image below. 

ImageView Only

Next, let's add a couple TextViews and see a few more ways to use these constraints. An optimal way of aligning two text fields to each other is to constrain the bottom of the text itself (not the Views that contain the text) to each other. This can be accomplished by using the rectangular anchor point within the TextView. Hover your mouse over the rectangular anchor point until it starts to slowly blink on and off. When the blinking starts, that's when you can grab the anchor point and drag it to your intended constraint point. This especially useful when you want to align texts of different sizes. Text Constraint

Finally, the Guidelines come into action. We are going to use them in two different different ways. First, suppose our designer requested two buttons at the bottom of our layout. The buttons each need to wrap_content in their layout_height, and the button on the left needs to fill one-third of the screen, horizontally, and the button on the right needs to fill the rest of the space, horizontally. We can simply place a vertical Guideline at 33% from the start of the layout and constrain the buttons to the edges of the activity and the Guideline.
Buttons With Guideline

Notice how the any_size sizing method is used here. It fills any remaining space that is not utilized by its peer view.

Another scenario, now the designer requested a change. The new requirement needs to wrap_content on our buttons both vertically and horizontally, but they have to be centered on the 1/3 and 2/3 vertical axes of our activity. Guidelines to the rescue again. We can adjust our constraints such that each button has its left and right side constrained to the same Guideline. This will center our button on the chosen guideline. 

Button Guideline Thirds

If a widget is constrained in a manner that is no longer needed or desired, you can simply hover the mouse over the anchor point from which the unwanted constraint comes from and click on the unneeded anchor point when it blinks red. This will delete the current constraint from that anchor point.

Take a moment to review the xml. Notice anything? Yep! We were able to complete this layout (albeit rather simple) without nesting a single layout!

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
    android:id="@+id/activity_main"
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.cheinz.blogscreenshots.MainActivity">

    <ImageView
        android:id="@+id/imageView"
        android:layout_width="0dp"
        android:layout_height="200dp"
        android:layout_marginEnd="16dp"
        android:layout_marginLeft="16dp"
        android:layout_marginRight="16dp"
        android:layout_marginStart="16dp"
        android:layout_marginTop="16dp"
        app:layout_constraintLeft_toLeftOf="@+id/activity_main"
        app:layout_constraintRight_toRightOf="@+id/activity_main"
        app:layout_constraintTop_toTopOf="@+id/activity_main"
        app:srcCompat="@drawable/CapTech"
        tools:layout_constraintLeft_creator="1"
        tools:layout_constraintRight_creator="1"
        tools:layout_constraintTop_creator="1"/>

    <TextView
        android:id="@+id/textView3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="32dp"
        android:text="Blogs:"
        android:textSize="18sp"
        app:layout_constraintLeft_toLeftOf="@+id/imageView"
        app:layout_constraintTop_toBottomOf="@+id/imageView"/>

    <TextView
        android:id="@+id/textView4"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="8dp"
        android:layout_marginStart="8dp"
        android:text="www.captechconsulting.com/insights/blog"
        app:layout_constraintBaseline_toBaselineOf="@+id/textView3"
        app:layout_constraintLeft_toRightOf="@+id/textView3"/>

    <Button
        android:id="@+id/button11"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="16dp"
        android:text="Button"
        app:layout_constraintBottom_toBottomOf="@+id/activity_main"
        app:layout_constraintLeft_toLeftOf="@+id/guideline16"
        app:layout_constraintRight_toLeftOf="@+id/guideline16"/>

    <android.support.constraint.Guideline
        android:id="@+id/guideline15"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        app:layout_constraintGuide_Percent="34"
        tools:layout_editor_absoluteX="130dp"
        tools:layout_editor_absoluteY="0dp"/>

    <android.support.constraint.Guideline
        android:id="@+id/guideline16"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        app:layout_constraintGuide_Percent="68"
        tools:layout_editor_absoluteX="261dp"
        tools:layout_editor_absoluteY="0dp"/>

    <Button
        android:id="@+id/button12"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="16dp"
        android:text="Button"
        app:layout_constraintBottom_toBottomOf="@+id/activity_main"
        app:layout_constraintLeft_toLeftOf="@+id/guideline15"
        app:layout_constraintRight_toLeftOf="@+id/guideline15"/>

</android.support.constraint.ConstraintLayout>
 

Final Few Features To Know About

Infer Constraints

Infer constraints is a neat feature that will attempt to automatically create constraints. Simply place a few widgets on your layout and click the Infer Constraints button and watch magic happen.

  Infer Constraints

Autoconnect

If you want to skip the step of having to click the 'Infer Constraints' button, you can turn on Autoconnect. This will attempt to automatically create constraints for widgets as you place them in your layout.

  Autoconnect

Convert To ConstraintLayout

Convert To ConstrainLayout is a feature which will automatically convert a non-ConstraintLayout over to a ConstraintLayout. In my opinion, this feature is probably the most error-prone feature based on my testing. It works well on very simple layouts, but produces inconsistent results on more complex layouts. My advice would be to give it a try and occasionally test with this feature. I'm sure the Google Tools team will eventually iron out its functionality and make it a very useful tool.

Final Thoughts

Although ConstraintLayout and the Layout Editor are still in their infancy, they certainly have great promise. The LE, even for a Preview release, is quite usable. Personally, I've encountered a few bugs, or what I thought was unintended behavior, but for the most part, it is effectively performing to a level which allows for a jump in and try approach. I recommend getting comfortable wth the new Layout Editor sooner rather than later, as it will be our only choice once it makes its way to the Stable Channel. As for the ConstraintLayout library, it is quite stable and seems to accomplish its goals of reducing/eliminating ViewGroup nesting. In my opinion, the ConstraintLayout and updated Layout Editor combination will vastly reduce layout development time (of course, with a little practice).

References

About the Author

Chris HeinzChris Heinz is a Software Engineer in CapTech’s Systems Integration practice area.  He has developed embedded systems in C/C++, server-side applications in Java, and now enjoys exploring the power and flexibility of the Android ecosystem.