22. Mar 2021Android

All about Constraint Layout helpers I.

Constraint layout is type of ViewGroup, which allows you to create complex layouts with flat view hierarchy. Full power of CL comes from his helpers.

Peter ŠulyAndroid developer

Group

The simplest of Constraint Layout helpers. Just controls visibility of multiple (or one) referenced views. Tends to be useful if you want to set multiple views to VISIBLE or GONE state, but don't want to wrap them in some ViewGroup wrapper so your XML structure can stay flat.

For referencing views inside Group constraint_referenced_ids attribute can be used.

app:constraint_referenced_ids="text,button"

app:constraint_referenced_ids="text,button"

In the following example, text's and button's visibility can be controlled by setting visibility to Group helper. E.g.

//Doing this somewhere in code shows text and button
group.visibility = View.VISIBLE 

//Doing this somewhere in code hides text and button
group.visibility = View.GONE
<androidx.constraintlayout.widget.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">

    <androidx.constraintlayout.widget.Group
	android:id="@+id/group"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:constraint_referenced_ids="text,button"/>

    <com.google.android.material.textview.MaterialTextView
        android:id="@+id/text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Android Text"
        app:layout_constraintTop_toTopOf="parent"/>

    <com.google.android.material.button.MaterialButton
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Android"
        app:layout_constraintTop_toBottomOf="@id/text"/>
    
</androidx.constraintlayout.widget.ConstraintLayout>

In case where one view is referenced from multiple groups, the declaration order in XML will define the final visibility (last group in XML has last word).

Layer

Practically the same as Group helper, but changes of translation, scale and rotation are supported.

E.g. rotating multiple views can look like this

image1.setOnClickListener {    layer.rotation = Random.nextInt(60).toFloat()}
<androidx.constraintlayout.widget.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:id="@+id/image1"
        android:layout_width="64dp"
        android:layout_height="64dp"
        android:src="@drawable/background_badge_green"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toStartOf="@id/image2"/>

    <ImageView
        android:id="@+id/image2"
        android:layout_width="64dp"
        android:layout_height="64dp"
        android:src="@drawable/background_badge_red"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toEndOf="@id/image1"
        app:layout_constraintEnd_toEndOf="parent"/>

    <androidx.constraintlayout.helper.widget.Layer
        android:id="@+id/layer"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:constraint_referenced_ids="image1, image2"/>

</androidx.constraintlayout.widget.ConstraintLayout>

Guideline

Invisible helper object for Constraint Layout (it's never displayed on device). Main purpose of guideline is to place the child of Constraint Layout at some specific location (e.g. 100dp from screen start or 25% from screen bottom...)

Guideline can be either Vertical (zero width, height of parent Constraint Layout) or Horizontal(width of parent Constraint Layout, zero height). You can use orientation attribute for defining orientation of Guideline.

android:orientation="vertical"

OR

android:orientation="horizontal"

The most important property of Guideline is it's position. Guideline can be positioned in 3 different ways using layout_constraintGuide_begin, layout_constraintGuide_end and layout_constraintGuide_percent attributes. These are affected by orientation also.

//100dp from start
android:orientation="vertical"
app:layout_constraintGuide_begin="100dp"

OR

//100dp from bottom
android:orientation="horizontal"
app:layout_constraintGuide_end="100dp"

OR

//14% from top
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.14"

Any direct child of Constraint Layout can be constrained to Guideline, but Guideline on it's own cannot have any constraints. Position of guidelines is only determined by mentioned attributes. Here is the example of Button positioned to 25% from top of the screen.

user interface preview of constraintlayout guidline
<androidx.constraintlayout.widget.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">

    <androidx.constraintlayout.widget.Guideline
        android:id="@+id/guideline"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="horizontal"
        app:layout_constraintGuide_percent="0.25" />

    <com.google.android.material.button.MaterialButton
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" 
        android:text="Android"
        app:layout_constraintTop_toTopOf="@id/guideline"
        app:layout_constraintBottom_toBottomOf="@id/guideline"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"/>

</androidx.constraintlayout.widget.ConstraintLayout>

Barrier

Barrier helper is similar to Guideline. Main difference between them is that the Barrier is flexible. It takes multiple views in constraint_referenced_ids attribute and creates virtual guideline based on the most extreme view from referenced views (most extreme view is the widest or the highest view). If width (or height) of most extreme view changes during runtime, barrier will automatically move according to it. Every Barrier needs to have barrierDirection attribute.

user interface preview of constraintlayout barrier end & bottom
app:barrierDirection="start"  //Barrier is positioned at the start of referenced views
app:barrierDirection="end"    //Barrier is positioned at the end referenced views
app:barrierDirection="top"    //Barrier is positioned above referenced views
app:barrierDirection="bottom" //Barrier is positioned below referenced views

Barrier tends to be useful when you want to constraint view below (or above, at the end, at the start) of another views. E.g. usecase, when button needs to be under textViews, no matter how long they are.You should notice that, you can constraint views to Barrier (unlike to Guideline).

user interface showing difference between barrier and guidline
<androidx.constraintlayout.widget.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">

    <androidx.constraintlayout.widget.Barrier
        android:id="@+id/barrier"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:barrierDirection="bottom"
        app:constraint_referenced_ids="text1,text2" />

    <com.google.android.material.textview.MaterialTextView
        android:id="@+id/text1"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="Android Text"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toStartOf="@id/text2"/>

    <com.google.android.material.textview.MaterialTextView
        android:id="@+id/text2"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="Android Text slightly wider Android Text slightly wider"
        app:layout_constraintStart_toEndOf="@id/text1"
        app:layout_constraintEnd_toEndOf="parent"/>

    <com.google.android.material.button.MaterialButton
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Android"
        android:layout_marginTop="16dp"
        app:layout_constraintTop_toBottomOf="@id/barrier"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"/>

</androidx.constraintlayout.widget.ConstraintLayout>

Did you like this article? Read more in the second part! Follow me on LinkedIn and stay in track.
 

Peter ŠulyAndroid developer