Android Constraint Layout

Swati Shah
4 min readNov 28, 2022

--

Constraint Layout allows you to create complex layouts with a flat hierarchy.

Every view must have at least two constraints: one horizontal and one vertical.

You can use constraints to achieve different types of layout behaviour:

Parent position:

Constraint side of a view to the corresponding edge of layout.

Order position:

Define the order of appearance for two views either horizontally or vertically. Eg:

app:layout_constraintLeft_toRightOf="@+id/buttonA"

This tells the system that we want the left side of button B to be constrained to the right side of button A.

Margins:

If side margins are set they will be applied to the corresponding constraints enforcing the margin as a space between target and the source side.

When a position constraint target’s visibility is View.GONE you can also indicate a different margin to be used eg: layout_goneMarginStart.

Centering positioning and bias:

app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"

In the above case the widget will end up being centered in the parent container.

Bias

To tweak the positioning in the above scenario to favour one side use bias.

app_layout_constraintHorizontal_bias="0.3"

Dimension constraints

You can define minimum and maximum sizes for ConstraintLayout

android:minWidth="30dp"

These will be used when dimensions are set to WRAP_CONTENT.

Widgets dimension constraints

You can specify dimensions using specific value eg: 30dp, WRAP_CONTENT or using MATCH_CONSTRAINT(added in 1.1) which is equivalent of 0dp.

Sometimes you want to use WRAP_CONTENT yet enforce constraints limiting the resulting dimension. In that case use

app:layout_constrainedWidth="true|false"

With a dimension set to MATCH_CONSTRAINT the default behaviour is to have the resulting size take all the available space. To modify this use

app:layout_constraint(Width|Height)_(min|max)

or

app:layout_constraint(Width|Height)_default="percent"
app:layout_constraint(Width|Height)_percent="0.3"

to set the size of this dimension as percentage of parent.

Ratio

You can define one dimension of widget as a ratio of the other one. You need to set at least one constrained dimension to 0dp (or MATCH_CONSTRAINT) and set the attribute

app:layout_constraintDimensionRatio="1:1"

Chains

Chains provide a group-like behaviour in a single axis(horizontally or vertically). Chains are controlled by attributes set on the first element of the chain.

Chain Style:

app:layout_constraint(Horizontal|Vertical)_chainStyle
  • CHAIN_SPREAD: The elements will be spread out (default style)
  • Weighted Chain: If some widgets are set to MATCH_CONSTRAINT they will split the available space
app:layout_constraint(Horizontal|Vertical)_weight="2"

For ex: on a chain containing two elements using MATCH_CONSTRAINT, with the first element using a weight of 2 and the second a weight of 1, the space occupied by the first one will be twice that of second element.

  • CHAIN_SPREAD_INSIDE: Endpoints of the chain will not be spread out
  • CHAIN_PACKED: Elements will be packed together

Alignment:

Align the edge of a view to the same edge of another view.

app:layout_constraintLeft_toLeftOf="@+id/textView"

Baseline Alignment:

Align the text baseline of view to the text baseline of another view.

app:layout_constraintBaseline_toBaselineOf="@+id/textView"

Constrain to a guideline:

Add vertical or horizontal guideline to which you can constrain views. Guide can be based of either dp units or percent.

Constrain to a barrier:

Barrier does not define its own position, instead the barrier position moves based on the position of view contained within it.

Difference between Barrier and Guideline:

Barrier’s position is flexible and always based on the size of the elements contained within it but Guideline’s position is always fixed

Suppose you want to place a button below two dynamic views in a way that if the views grow, the button needs to move below them. Then create a barrier referencing the dynamic views. Add a constraint to the button to set its top to top of barrier.

Guideline
<androidx.constraintlayout.widget.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"
app:layout_optimizationLevel="none"
android:layout_height="match_parent">

<EditText
android:id="@+id/edit_text1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:background="#AAA"
android:text="Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
android:textSize="16sp"
app:layout_constraintEnd_toStartOf="@+id/edit_text2"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

<EditText
android:id="@+id/edit_text2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:background="#DDD"
android:text="The quick brown fox jumped over the lazy dog"
android:textSize="16sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/edit_text1"
app:layout_constraintTop_toTopOf="parent" />

<androidx.constraintlayout.widget.Barrier
android:id="@+id/barrier2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:barrierDirection="bottom"
app:constraint_referenced_ids="edit_text1,edit_text2" />

<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:text="Button"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/barrier2" />


</androidx.constraintlayout.widget.ConstraintLayout>

This way even if the edit text grows, the Button remains below them.

But suppose you want that the dynamic views should be restricted to only 50% of the screen height, then add a guideline to your view.

Guideline
<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"
app:layout_optimizationLevel="none"
android:layout_height="match_parent">

<EditText
android:id="@+id/edit_text1"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:background="#AAA"
android:text="Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
android:textSize="16sp"
app:layout_constraintEnd_toStartOf="@+id/edit_text2"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@id/guideline"/>

<EditText
android:id="@+id/edit_text2"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:background="#DDD"
android:text="The quick brown fox jumped over the lazy dog"
android:textSize="16sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/edit_text1"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@id/guideline"/>

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

<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:text="Button"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/guideline" />


</androidx.constraintlayout.widget.ConstraintLayout>

--

--