Android ConstraintLayout

Filed Under: Android

In this tutorial, we will discuss the various attributes of Android ConstraintLayout and learn how to position views based on constraints both programmatically as well as through XML in our Android Application.

Android ConstraintLayout

ConstraintLayout is the latest ViewGroup introduced on the Android block.
They are RelativeLayout with superpowers. They were introduced to prevent too many nested layouts. They flatten out the layouts.

Superpowers are:

  • Positioning sides of a view relative to sides of another view.
  • ConstraintSets
  • Setting horizontal/vertical bias
  • Chaining and grouping views together.
  • Barriers
  • Setting the percent of width or height the view would occupy on the screen.
  • Circular positioning the views.

To use Android ConstraintLayout please add the following dependency in your build.gradle file.


implementation 'com.android.support.constraint:constraint-layout:1.1.2'

Positioning Views Relative to one another

Let’s drag and drop a view into the center of the screen:

android-constraint-layout-xml-basic

As you see in the above gif, the Button is positioned in the center of the screen with each side having the constraint to the parent view.

We can remove either a single constraint or all as shown below:

android-constraint-layout-remove-constraints

The cross is used to remove ALL constraints. Clicking the circle would remove the constraint of that side.
Drag the same circle to create a new constraint.

android-constraint-layout-set-constraints

WOW! That’s so much of power.
Let’s see how xml version of the above layout design looks;


<?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"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">


    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        android:text="Button"
        app:layout_constraintStart_toEndOf="@+id/button2"
        app:layout_constraintTop_toBottomOf="@+id/button2" />

    <Button
        android:id="@+id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        android:text="Button"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>

parent refers to the root view.

Following is the list of XML attributes to position views by each other’s sides(top/left/bottom/right).

android-constraint-layout-xml-attributes

We can align two views by their baselines as well, as shown below:

android-constraint-layout-baseline

Let’s set Constraints Programmatically. For this ConstraintSet is used.

ConstraintSet

ConstraintSet instance is defined to set the constraints programmatically.
Following is the code from the MainActivity.kt class. activity_main.xml does not contain anything inside the ConstraintLayout tag.


package net.androidly.androidlyconstraintlayout

import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.support.constraint.ConstraintLayout
import android.support.constraint.ConstraintSet
import android.widget.Button
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity() {

    val ID_1 = 1
    val ID_2 = 2

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val button = Button(this)
        button.text = "Button"
        button.id = ID_1
        val lp = ConstraintLayout.LayoutParams(ConstraintLayout.LayoutParams.WRAP_CONTENT, ConstraintLayout.LayoutParams.WRAP_CONTENT)
        button.layoutParams = lp
        constraintLayout.addView(button)

        val button2 = Button(this)

        button2.text = "Button2"
        button2.id = ID_2
        constraintLayout.addView(button2)

        val constraintSet = ConstraintSet()
        //Copy all the previous constraints present in the constraint layout.
        constraintSet.clone(constraintLayout)

        constraintSet.connect(ID_1, ConstraintSet.TOP, ConstraintSet.PARENT_ID, ConstraintSet.TOP)
        constraintSet.connect(ID_1, ConstraintSet.BOTTOM, ConstraintSet.PARENT_ID, ConstraintSet.BOTTOM)
        constraintSet.connect(ID_1, ConstraintSet.LEFT, ConstraintSet.PARENT_ID, ConstraintSet.LEFT)
        constraintSet.connect(ID_1, ConstraintSet.RIGHT, ConstraintSet.PARENT_ID, ConstraintSet.RIGHT)

        constraintSet.connect(ID_2, ConstraintSet.BOTTOM, ID_1, ConstraintSet.TOP)
        constraintSet.connect(ID_2, ConstraintSet.LEFT, ConstraintSet.PARENT_ID, ConstraintSet.LEFT)
        constraintSet.connect(ID_2, ConstraintSet.RIGHT, ConstraintSet.PARENT_ID, ConstraintSet.RIGHT)
        constraintSet.applyTo(constraintLayout)

    }
}

clone is used to copy all the previous constraints defined in the constraint layout.
In the above code, we set Button in the center of the layout and Button2 on top of it.
connect function has an additional fifth parameter as well for margin values.

The equivalent of parent in xml is ConstraintSet.PARENT_ID.

Horizontal and Vertical Bias

An image is worth a thousand words.

android-constraint-layout-bias

The attributes are: app:layout_constraintVertical_bias and app:layout_constraintHorizontal_bias. They expect a value between 0 and 1. 0.5 is the default value.

Chaining and Grouping

Chains are used to evenly space views horizontally or vertically.

android-constraint-layout-chains

The xml version is :


<?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"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/constraintLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">


    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button"
        app:layout_constraintBottom_toTopOf="@+id/button5"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/button4" />

    <Button
        android:id="@+id/button4"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="8dp"
        android:text="Button"
        app:layout_constraintBottom_toTopOf="@+id/button"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_chainStyle="spread_inside" />

    <Button
        android:id="@+id/button5"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="8dp"
        android:text="Button"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/button" />
</android.support.constraint.ConstraintLayout>

The chain styles can be:

  • spread
  • spread inside
  • packed
  • weighted

weighted requires setting a weight on each view. The view with most weight occupies the most space.
app:layout_constraintHorizontal_weight is used to set the weights in a horizontal chain.

Groups are used to toggle the visibility of a group of views together.
Add the following inside the previous constraint layout


<android.support.constraint.Group
              android:id="@+id/group"
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:visibility="invisible"
              app:constraint_referenced_ids="button4,button9" />

Barriers

A Barrier is used to create a virtual divider or a guideline on a group of views based on the largest view in the group.
This virtual divider can be connected with other child views.

android-constraint-layout-barrier


<?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"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/constraintLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">


    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:text="TextView\nTextView\nTextView\nTextView\nTextView"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/textView2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:text="TextView\nTextView\nTextView\nTextView\nTextView\nTextView\nTextView\nTextView\nTextView"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toEndOf="@+id/textView"
        app:layout_constraintTop_toTopOf="parent" />

    <android.support.constraint.Barrier
        android:id="@+id/barrier"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:barrierDirection="bottom"
        app:constraint_referenced_ids="textView, textView2" />

    <Button
        android:id="@+id/button7"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        android:text="Button"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="@+id/barrier" />

</android.support.constraint.ConstraintLayout>

Percentage Width and Height

Constraint Layouts support percentage width and height too just like LinearLayouts.


<?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"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/constraintLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">


    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:text="TextView\nTextView\nTextView\nTextView\nTextView"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/textView2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:text="TextView\nTextView\nTextView\nTextView\nTextView\nTextView\nTextView\nTextView\nTextView"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toEndOf="@+id/textView"
        app:layout_constraintTop_toTopOf="parent" />

    <android.support.constraint.Barrier
        android:id="@+id/barrier"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:barrierDirection="bottom"
        app:constraint_referenced_ids="textView, textView2"
        tools:layout_editor_absoluteY="331dp" />

    <Button
        android:id="@+id/button7"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        android:text="Button"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="@+id/barrier" />

</android.support.constraint.ConstraintLayout>

For percentage width, you need to set the Button’s width to 0dp and vice-versa for percentage height.

android-constraint-layout-percentage-width

Circular Positioning

We can position the views at radial distances and angles from one another.
app:layout_constraintCircle is used to reference the view which would act as the center of the circle.
app:layout_constraintCircleRadius and app:layout_constraintCircleAngle is used to set the radius distance from the center of the circle and the angle at which our view would be positioned.


<?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"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/constraintLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">


    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="8dp"
        android:layout_marginStart="8dp"
        android:text="Hello"
        android:textSize="18sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/textView2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hi"
        android:textSize="18sp"
        app:layout_constraintCircleRadius="100dp"
        app:layout_constraintCircleAngle="45"
        app:layout_constraintCircle="@+id/textView"/>


    <TextView
        android:id="@+id/textView3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Another"
        android:textSize="18sp"
        app:layout_constraintCircleRadius="100dp"
        app:layout_constraintCircleAngle="135"
        app:layout_constraintCircle="@+id/textView"/>


</android.support.constraint.ConstraintLayout>

android-constraint-layout-circular-positioning

This brings an end to this tutorial on ConstraintLayout.

Leave a Reply

Your email address will not be published. Required fields are marked *

close
Generic selectors
Exact matches only
Search in title
Search in content
Search in posts
Search in pages