So you know that reducing the amount of layers in your layout is crucial for your layout efficiency, and you also know that ConstraintLayout is the right solution for that (if you don’t, go read Understanding the performance benefits of ConstraintLayout).

At a glance, it seems that ConstraintLayout is what we all have dreamt about, an elastic layout with efficiency processing. But when we really come to replace our good old RelativeLayout with ConstraintLayout, the problems start to arise.

A real-life mobile development problem

Let’s say you want to build a page that has the following structure:

  • Button at the bottom
  • Some explanation TextView above the button
  • ImageView centered in the space between TextView and the top of the page
  • And one more thing… your UX designer wants TextView to disappear in some cases, but ImageView should not be moved when it happens

Such a layout will  look like this:

 

With Relative and Linear layouts the XML representation will probably look something like the following:

<?xml version="1.0" encoding="utf-8"?>

<RelativeLayout

      xmlns:android=”http://schemas.android.com/apk/res/android”

      android:layout_width=”match_parent”

      android:layout_height=”match_parent”>

 

 

  <RelativeLayout

      android:layout_width=”match_parent”

      android:layout_height=”match_parent”

      android:layout_above=”@id/textView”>

 

 

      <ImageView

          android:layout_width=”wrap_content”

          android:layout_height=”wrap_content”

          android:src=”@mipmap/ic_launcher”

          android:layout_centerInParent=”true”/>

 

  </RelativeLayout>

 

 

  <TextView

      android:id=”@+id/textView”

      android:layout_width=”wrap_content”

      android:layout_height=”wrap_content”

      android:layout_above=”@+id/button”

      android:layout_centerHorizontal=”true”

      android:layout_marginBottom=”10dp”

      android:text=”Send your request”/>

 

  <Button

      android:id=”@+id/button”

      android:layout_width=”match_parent”

      android:layout_height=”wrap_content”

      android:layout_alignParentBottom=”true”

      android:layout_alignParentLeft=”true”

      android:layout_alignParentStart=”true”

      android:layout_margin=”10dp”

      android:text=”Submit”/>

 

 

</RelativeLayout>

You see what just happened? In order to achieve that (using the traditional layouts) we had to add an internal RelativeLayout and center the ImageView relative to that inner RelativeLayout!! (there goes your redundant extra layout…)

 

The basics of centering in ConstraintLayout

 

The easiest way to center an item using ConstraintLayout is:

  • switch to design mode
  • press right click on the view you want to center, and then choose the kind of center you want

 

Let’s take a look at the code that is being generated when centering an ImageView in ConstraintLayout, using the method we described above:

 


<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”>

 

   <ImageView

       android:layout_width=”wrap_content”

       android:layout_height=”wrap_content”

       android:layout_centerInParent=”true”

       android:src=”@mipmap/ic_launcher”

       app:layout_constraintBottom_toBottomOf=”parent”

       app:layout_constraintEnd_toEndOf=”parent”

       app:layout_constraintStart_toStartOf=”parent”

       app:layout_constraintTop_toTopOf=”parent”/>

</android.support.constraint.ConstraintLayout>

 

 

The last 4 lines of the ImageView are where the magic happens.

You see, in order to center an item vertically, all we need is the following 2 lines:

app:layout_constraintTop_toTopOf=“parent”

app:layout_constraintBottom_toBottomOf=”parent”

 

What those lines mean, is that the item should position itself in the following way:

Stick its bottom to the bottom of the parent, and also stick its top to the top of the parent.

That way, when you use both constraints, the item should be in the center.

There is no other way it can fulfill both constraints.

The same goes for horizontal centering, of course…

 

Now, here is the problem

 

We know how to position items with simple constraints, and we also know how to center items relative to the main parent, but we want to gain the same results as we had with the traditional layouts.

 

To illustrate the problem, we’ll take a look at these two layouts:

The left one is what we just built using the traditional way, and the right one is a first draft of an attempt to do the same with ConstraintLayout.

 

Can you see the difference?

As we thought, the ImageView is centered relative to the main parent.

It is not centered in the space between the top of the screen and the TextView.

 

Here is the code for the current ConstraintLayout draft:


<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”>

  <ImageView

      android:layout_width=”wrap_content”

      android:layout_height=”wrap_content”

      android:layout_centerInParent=”true”

      android:src=”@mipmap/ic_launcher”

      app:layout_constraintEnd_toEndOf=”parent”

      app:layout_constraintStart_toStartOf=”parent”

      app:layout_constraintBottom_toBottomOf=”parent”

      app:layout_constraintTop_toTopOf=”parent”/>

  <TextView

      android:id=”@+id/textView”

      android:layout_width=”wrap_content”

      android:layout_height=”wrap_content”

      app:layout_constraintBottom_toTopOf=”@+id/button”

      app:layout_constraintEnd_toEndOf=”parent”

      app:layout_constraintStart_toStartOf=”parent”

      android:layout_marginBottom=”10dp”

      android:text=”Send your request”/>

  <Button

      android:id=”@+id/button”

      android:layout_width=”match_parent”

      android:layout_height=”wrap_content”

      app:layout_constraintEnd_toEndOf=”parent”

      app:layout_constraintStart_toStartOf=”parent”

      app:layout_constraintBottom_toBottomOf=”parent”

      android:layout_margin=”10dp”

      android:text=”Submit”/>

</android.support.constraint.ConstraintLayout>

So up until now, we know how to put items in the center of a ConstraintLayout.

We also know that it does not help us center items inside an inner part of the main parent. We also know how to do it in the traditional way.

The question now is, how can we combine these together?

How can we divide our ConstraintLayout  into separate sections, and make our constraints

relative to the sections and not to the main parent?

 

Guideline

Meet Guideline. This feature is just the tool we need for our case. It makes a line across our layout, so we can build our constraints upon it, but the real cool thing is, that it is just a line made for our needs at design time, and is not going to be rendered.

 

Using this tool we can divide the main (and single) ConstraintLayout into sections as we like, and use those sections just as we used inner layouts Only that those sections are not going to be visible to the user, nor consuming processing resources.

 

Cool, how can I get one?

 

Use Guideline in your layouts

 

Again, the easiest way to add Guideline is switching to design mode and searching for this button  on the lowest bar (at the top of the screen).

After pressing the Guideline button you will have to choose one (horizontal/vertical), and voilà…

 

Switch to text mode and search for your new Guideline, position it as you wish.

Now we can make the magic…

We are left with a well-defined area on which we can center our components.

 

Let’s take a look at the code once again.

 

Final design

 

We are going to take a look at the xml from the example above.

For now we will cut the ImageView off, and insert a horizontal Guideline.

 

The xml will look like this:


<?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.Guideline

      android:id=”@+id/guideline”

      android:layout_width=”wrap_content”

      android:layout_height=”wrap_content”

      android:orientation=”horizontal”/>

  <TextView

      android:id=”@+id/textView”

      android:layout_width=”wrap_content”

      android:layout_height=”wrap_content”

      android:layout_marginBottom=”10dp”

      android:text=”Send your request”

      app:layout_constraintBottom_toTopOf=”@+id/button”

      app:layout_constraintEnd_toEndOf=”parent”

      app:layout_constraintStart_toStartOf=”parent”/>

  <Button

      android:id=”@+id/button”

      android:layout_width=”match_parent”

      android:layout_height=”wrap_content”

      android:layout_margin=”10dp”

      android:text=”Submit”

      app:layout_constraintBottom_toBottomOf=”parent”

      app:layout_constraintEnd_toEndOf=”parent”

      app:layout_constraintStart_toStartOf=”parent”/>

 

</android.support.constraint.ConstraintLayout>

The next step is to position our Guideline right above TextView. We will do that by dragging the Guideline from A to B.

A

B

 

  

In our case, the Guideline is:


<android.support.constraint.Guideline

  android:id=”@+id/guideline”

  android:layout_width=”match_parent”

  android:layout_height=”wrap_content”

  android:orientation=”horizontal”

  app:layout_constraintGuide_end=”86dp”

  />

 

The final step is to reinsert the ImageView into the ConstraintLayout.

Only now, we are centering it relative to the space between the Guideline and the top of the layout.


<ImageView

  android:layout_width=”wrap_content”

  android:layout_height=”wrap_content”

  android:layout_centerInParent=”true”

  android:src=”@mipmap/ic_launcher”

  app:layout_constraintBottom_toBottomOf=”@+id/guideline”

  app:layout_constraintEnd_toEndOf=”parent”

  app:layout_constraintStart_toStartOf=”parent”

  app:layout_constraintTop_toTopOf=”parent”/>

 

Finally, the ImageView is centered as desired, even if the TextView is gone.

 

 

Note: We could have constrained the ImageView to the TextView and the top of the page, that way, the ImageView would be centering as desired, but it was more complicated to handle when the TextView was gone.

 

The source code can be found on github.