ConstraintLayout In Jetpack Compose

Samir Shaikh
6 min readOct 31, 2022

--

Photo by Hal Gatewood on Unsplash

It’s been a year since we got the first stable release of jetpack compose and from its first release we know how good it is to write code in jetpack compose. We can achieve so much more in jetpack with less code as compared to the old view system.

ConstraintLayout:

ConstraintLayout is a layout that allows you to place composables relative to other composables on the screen. It is an alternative to using multiple nested Row, Column, Box and custom layout elements. ConstraintLayout is useful when implementing larger layouts with more complicated alignment requirements.

So 💁🏻, In a nutshell, Jetpack compose ConstraintLayout is similar to the ConstraintLayout that we have already used in our legacy view system. We can position our composable element relative to its sibling composable and/or its parent. Also, we can avoid multiple nesting of custom layout elements like Row,Column etc. and write much more readable code.

To use ConstraintLayout in compose, we need to add its dependency in build.gradle along with the jetpack compose dependency.

def compose_version = "1.0.1" //update it with the latest version
implementation "androidx.constraintlayout:constraintlayout-compose:$compose_version"

To see how ConstraintLayout helps in real life we are going to convert a simple composable layout shown below (build with row and column) to ConstraintLayout. 😎

Let’s Code… 🧑🏻‍💻

Here we have used a Row to wrap user image, a Column which contain two Text composable for our title and subtitle and lastly, an Icon for the action button.

Let's see how we can avoid nesting of Row and Column here using ConstraintLayout.

Here, (As obvious 🤓) we have used ConstraintLayout as our root layout. On line 10 we created four references using createRefs() and assigned them to each composable accordingly.

In each composable, we have used constrainAs() a modifier where we use these references to position the composable relative to other composable and/or its parent.

And guess what our new layout looks like…..

Just like the old one 😉.

Note: Maintaining a flat view hierarchy for a better performance is not a concern in Compose.

ConstraintLayout is great, isn’t it? but that's not it. It provides different methods/features that help us build more interactive designs.

  • Guidelines
  • Barriers
  • Chains

Guidelines:

Guidelines are small visual helpers. In easy words, some invisible lines that we can create and use to position a composable element at a specific dp or percentage inside the parent composable. We can create vertical and horizontal guidelines using the following methods.

// Create guideline from the start of the parent at 50% the width of the Parent Composable
createGuidelineFromStart(0.5f)
// Create guideline from 16 dp from the end of the parent
createGuidelineFromEnd(16.dp)
// Create guideline from 16 dp from the top of the parent
createGuidelineFromTop(16.dp)
// Create guideline from the bottom of the parent at 10% the height of the Parent Composable
createGuidelineFromBottom(0.1f)

To see it in an action we are going to build the following UI in compose.

Here we are positioning two buttons in such a way that each of them occupies 50% width of the parent.

Let's see this in the code. 👀

Here, we have used createGuidelineFromStart(0.5f) to create a vertical guideline from the start of the parent at 50% of the width. If you look at the above UI screenshot closely, you will find a vertical dashed line (Yes, it’s our guideline) in the middle.

For the Cancel button, we have linked its start to parent.start and end to middleGuideline. Similarly, for the Save button, we linked its start to middleGuideline and end to parent.end. To occupy the available width we have used width = Dimenstion.fillToConstraints in both the composable (i.e. cancel and save button).

Barriers:

Barriers create a virtual guideline by taking the maximum width or height of reference composable on a specific end.

Let’s understand this with a diagram.

So in the above image we have two boxes on the left-hand side called First Box and Second Box and we have a Third Box that we are placing at the extreme edge of either first box or second box. Here, the barrier helps us to find the extreme edge on the left-hand side and we don’t have to do any calculations to find starting position of Third Box.

Let's see some code examples for Barriers. 🧐

On line 12 we have created a barrier using createEndBarrier() and passed references to the green and red boxes in it. To align Gray Box (Third box) we have linked it start to endBarrier (i.e. Line 44).

If you preview this in the android studio it will look something like this.

Barrier Example in ConstraintLayout

Just like guidelines, we can create vertical and horizontal barriers using the following methods. createTopBarrier(), createBottomBarrier(), createEndBarrier(), createStartBarrier() .

Chains:

Chain is used to manage spacing between the composable elements in a group on a single axis (horizontally or vertically). To do that these composable should have constraints on each other. We can create a chain using createVerticalChain or createHorizontalChain method, both of them accept references to composable present in the chain and a ChainStyle.

ChainStyles is used to deal with the spacing between composable in a chain. Right now we can create 3 types of chains.

  • ChainStyle.Spread: As the name suggests, it spread space evenly across all the composable in the chain including free space before the first composable and after the last composable.
ChainStyle.Spread
  • ChainStyle.SpreadInside: Here, Space is distributed evenly across all the composable in the chain. It doesn’t leave any space before the first composable and after the last composable.
ChainStyle.SpreadInside
  • ChainStyle.Packed : It distributes space before the first composable and or after the last composable and doesn’t leave any space between the composable elements and places content in the middle of the parent.
ChainStyle.Packed

We can also pass bias (a float value between 0 to 1) inChainStyle.Packed . where 0 will place the group of composable at the start of the screen and 1 will place the group of composable at the end of the screen. Here, default bias is 0.5f which places the composable in the middle.

I hope 🤞🏻 you enjoyed reading my article and learned something new. If you like this article give it a clap and share it with your android buddies. Also, if you have any suggestions or want me to cover any topic, feel free to drop a comment.

Thank you!✌️

--

--

Samir Shaikh
Samir Shaikh

Written by Samir Shaikh

SSE — Android @Paytm | Ex The Parent Inc | Kotlin | Java | Android | Jetpack Compose

No responses yet