In this codelab, you'll learn about ConstraintLayout—a new type of layout available in the Android Support repository built on top of a flexible constraint system. By the end of this codelab, you'll be able to play with the layout editor in Android Studio and build a relatively complex layout.

What you'll learn

What you'll need

How will you use this tutorial?

Read it through only Read it and complete the exercises

How would rate your experience with building Android apps?

Novice Intermediate Proficient

To download the sample code, you can either:

Download ZIP

...or clone the GitHub repository from the command line by using the following command:

$ git clone https://github.com/googlecodelabs/constraint-layout.git

First, let's see what the finished sample app looks like. With the code downloaded, the following instructions describe how to open the completed sample app in Android Studio. Please note that the sample requires Android Studio 2.2 preview.

  1. Go to File > New > Import Project and select the constraint-layout-start directory from the sample code folder that you downloaded earlier.
  2. Click theGradle sync button.
  3. Open res/layout/activity_main_done.xml from the Project pane.
  4. Choose the Design tab to see the final layout.
  5. Vary the "Virtual Device to render the layout with" on the top left of the UI Builder to see the layout in different form factors.

Optional:

If you intend to run this on an Android device, go to MainActivity.java and ensure that setContentView method is pointing to activity_main_done.xml

 setContentView(R.layout.activity_main_done);

Plug in your Android device and click the Run button. You should see the constraint-layout screen appear on the emulator or connected device.

Frequently Asked Questions

The layout engine uses constraints specified for each widget to determine their positions within the layout. You can specify the constraints either manually or automatically by inference within the Android Studio layout editor. To understand constraints better, let's look at the basic handles available on a selected widget.

Constraints

Constraints help you keep widgets aligned. You can use anchors, such as the constraint handles described below, to determine alignment rules between various widgets. For example, setting a constraint from the left constraint handle of button 2 (see figure A below) to the right constraint handle of button 1 means that the button 2 widget will be positioned 56dp to the right of button 1.

Figure A.

Types of Handles:

Figure B. In this widget, we see the different handles.

Resize Handle: Similar to other design/draw applications you may have used, the resize handles allow you to resize the widget.

Side Constraint Handle: The side constraint handles, represented as circles on the sides of each widget, let you specify the location of the widget. For example, you can use a widget's left side constraint handle to always be to the right of another widget by 24dp. These are also referred to as anchors throughout this codelab.

Baseline Constraint Handle:

The baseline constraint handle helps you align the text fields of any two widgets, irrespective of the widget sizes. This is helpful for example, when you have two widgets of different sizes but want the text inside to be aligned horizontally.

Now you're ready to build on top of the starter project and build your constraint layout.

Open the res/layout/activity_main_start.xml from the left navigation bar.

Including the dependency on constraint-layout

The constraint-layout is built as a separate support library that works on all Android versions back to Android 2.3 (Gingerbread). The starter app already includes the dependency in app/build.gradle. For apps that you intend to build with ConstraintLayout, add the following compile dependency:

dependencies {
  ...
  compile 'com.android.support.constraint:constraint-layout:1.0.0-beta4'
}

Navigate to res/layout/activity_main_start.xml

The XML version of the layout already has an empty ConstraintLayout element included in the codelab project. ConstraintLayout was built from the ground up to be used in conjunction with the UI Builder as we believe it makes for a more intuitive and powerful experience. Nonetheless, you still have access to, and can edit, the corresponding XML.

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

</android.support.constraint.ConstraintLayout>

Switch to the Design view shown as a tab at the bottom of the editor window.

Add an ImageView to the layout

The first task is to add an ImageView to the layout. In the design window, find the ImageView on the Palette and drag it into the layout.

As soon as an ImageView is dragged onto the layout, the UI Builder asks for a resource to use. The constraint-layout-start sample already includes resources to make it convenient for the codelab. Go ahead and choose the @drawable/singapore resource.

Once selected, the ImageView appears on the layout you can click and hold the corner to resize the image as mentioned in the 'Constraint System Overview'

Add a TextView to the layout

Now let's drag a TextView from the palette onto the layout.

We see a few warnings in the UI Builder which are due to missing contentDescription attribute on the ImageView and the hardcoded text on the TextView. Content Description attributes are important for building accessible applications. For this codelab, let's use an already available resource @string/dummy for the attribute.

On the right, an Inspector pane lets you change the various attributes of the selected widget.

  1. Select the ImageView and add @string/dummy into it's contentDescription attribute.
  2. In the Inspector pane, you can also see the other attributes of the ImageView. Change the scaleType to be centerCrop for the purposes of this codelab.
  3. Next, we select the TextView and use the Inspector pane to modify the text value of the TextView to be @string/singapore.

At this point, we have two views in the layout. In the next section, we'll learn about how to create constraints between the views.

To create a constraint, you need to click and hold the mouse on a given handle, and drag it to another widget's constraint handle. Once the anchor is green, you can release the mouse to finalize the constraint creation.

Before we start, ensure that we have an ImageView and a TextView in the layout. Our goal here is to create constraints between the ImageView, the container and the TextView widgets already on the layout.

Let's assume that we want the TextView to be below the ImageView in our final layout. To accomplish this, we can create a constraint between the top anchor of the the TextView and the bottom anchor of the ImageView as shown.

The next step is to create a constraint between the top anchor of the ImageView to the top of the layout.

Finally, we can also use the left and right constraints to anchor the ImageView at the center of the layout.

This section showed the basics of how to create constraints between widgets by dragging connection lines. At this point you can explore the views and the UI Builder by adding other elements. In the next section we'll learn about the Inspector.

In this section we take a look at the view Inspector. The Inspector is on the right side of the UI Builder. In addition to listing the various properties of the selected widget, it also shows how the view is aligned and any constraints.

The UI Builder should look like the following.

The inspector shows the widget in the center in a square block. The following section describes the various elements and their uses.

Margins: To the left, right, top and bottom outside the widget are the margins. You can change the margins by clicking on the value and setting it to a different value. In the screenshot above, the margins are set to 16dp.

Deleting a constraint: Clicking on the lines connecting the widget to the container in the Inspector, also gives you an option to delete the constraint. Note that deleting a constraint can also be accomplished by clicking on the existing constraint handle.

Positioning the widget relative to constraints: When you have at least two opposing connections on a widget, such as the top and the bottom, or the left and the right, you can see a slider which lets you adjust the position of the widget along the axis of the opposing connections. This is also known as horizontal or vertical bias. You can adjust the horizontal and vertical bias and change the orientation to see that the bias is maintained. Alternatively this can also be achieved by moving the widget to the desired location.

Go ahead and change the vertical bias to 75% and the horizontal bias to 75%. The image below can be used as a guide.

Controlling the inner dimensions of the widget: The inner lines within a widget let you control the dimensions. You can click on the particular lines to see it in action.

Here is a zoomed in view of the widget in the Inspector pane. Clicking on the inner lines of the inspector pane widget cycles through the options mentioned below.

Fixed: This option lets you specify the width/height of the widget.

AnySize: This option lets the widget occupy all available space to satisfy the constraint. In other words, this is more like match constraint. This is different from match_parent, which makes the widget occupy all available space of the parent view.

Wrap Content: This option only expands to fill the widget with the contained element such as text or a drawable.

To view and edit all other attributes for a given widget, click at the top right of the Properties pane.

In this section, we explored the Inspector. The goal of the Inspector is to let you edit all properties and constraints without leaving the UI Builder.

Autoconnect, as the name suggests, automatically creates connections between widgets. It's important to understand that the Autoconnect feature tries to create connections to the neighboring widgets.

Before we get started with this section, ensure that:

  1. Open res/layout/activity_main_autoconnect.xml from the Project pane. Ensure that you select the "Design" tab.
  2. Autoconnect is enabled

Next we select the ImageView and center it in the layout by dragging it until the guidelines are shown. A couple of seconds after it is centered, autoconnect kicks in and creates constraints with the top, left, bottom and right of the container, as shown in the animation below.

Here we have a single ImageView on the layout and we see how Autoconnect creates the constraints.

Here are the steps for the next part of this section. For guidance, the animation above shows the steps used below:

  1. Align the ImageView to be placed at the top and use the Inspector (AnySize) to ensure that it expands to fill the width of the parent.
  2. Place two buttons at the bottom right corner of the layout. Use the Inspector pane to change the text attribute of the rightmost button to @string/upload and the one to the left of it to @string/discard.
  3. Drag a TextView and a Plain Text from the palette and place them on the layout.
  4. Adjust the TextView and Plain Text field to be 48dp apart. In a few seconds, Autoconnect creates the constraints to the widgets.
  5. Similarly select the upload button and place it close to our right margin and we let Autoconnect do the rest.
  6. Lastly place the discard button 32dp away from the upload button.

As an exercise, also move the TextView 48dp below the ImageView. To do this select the TextView and move until it's 48dp below the ImageView.

It's important to understand that Autoconnect only creates constraints for the widget being currently moved.

Autoconnect aids you by connecting to the nearest widgets which is helpful in many situations. There are cases where Autoconnect does not achieve the desired behavior, and developers should either use manual constraints or Inference to build their ConstraintLayout. Inference will be discussed in the next step of the codelab.

The Inference engine aids developers by creating constraints among elements added in the layout. The constraints created by Inference depend on the types of elements added to the layout and their sizes.

Setup

For this step, we start with the layout/activity_main_inference.xml layout. Open the layout file in the Design view. By default, the layout in this file defines the following:

What you'll learn

Understand the UI Builder icon actions

Since we'll be using some of these options, this is a good time to look at the actions available on the UI Builder.

Delete all constraints. This is helpful when you want to redo all the constraints in your layout in a different way.

Create constraints using inference. The inference engine tries to find and create optimal connections based on various factors such as the positions of the widgets and their size.

Expands the widget horizontally to satisfy constraints.

Expand the widget vertically to satisfy constraints.

Adding a TextView that occupies available space

Our goal is to add a TextView for the description of the image. We already have a @string/singapore_description which spans multiple lines.

  1. First, drag a TextView from the palette and place it below the settings text view.
  2. Use the action to expand the view horizontally to match guidelines.
  3. Use the action to expand vertically to fill available vertical space.

Using the Inference action

Now that you have the TextView in the layout, you are ready to see Inference in action.

Click the infer constraintsaction to create constraints using Inference.

The inference engine creates constraints among all the views in the layout. Your final layout should look like the following:

Once the constraints are created, you can modify the "virtual device to render with" by clicking on the button at the top left of the UI Builder. Choose a different device such as Nexus 6P or Nexus 9 to see that the layout renders correctly.

You've now seen the entire spectrum of using the constraint system: creating manual constraints, constraints using auto-connect, and constraints using the Inference engine.

Auto-connect and Inference aid you by having the layout engine figure out how to create constraints for various elements of your UI. You are then free to further modify the constraints created either by Auto-connect or the Inference engine as you see fit.

What we've covered