Matured Constraint Layout in Jetpack Compose | by Siva Ganesh Kantamani | Apr, 2022

My History with Constraint Layout in Compose

Back in 2020 when Jetpack Compose is still in the early stages, I wrote an article about constraint layout in Jetpack Compose. You can read about it from here if you’re interested(not a pre-requisite), but the way constraint layout matured since then makes it entirely different from back then and the improvement actually makes sense.

This article is not about the comparison, it’s about how to use matured constraint layout in today’s Jetpack Compose to design complicated composable. I’m going to focus on four crucial concepts of constraint layout:

1. Basics — Simple Contraints
2. Guidlines
3. Barriers
4. Bias

Before going any further lemme give you a brief explanation of the four concepts. Constraint layout is not a new concept in AndroidDev, it’s actually inherited from traditional android development to Jetpack Compose.

Basics — Simple Constraints

Simple constraints are nothing but positioning a view with certain constraints(relations) to its parent or sibling views.

Guidelines

Guidelines are nothing but invisible lines that you can place in the layout and constrain the views to it.

Barriers

Barriers are similar to Guidelines, but with barriers, you can constrain a view with multiple views via a single source. If it’s a bit difficult to understand don’t worry, we’re going to explore things in-depth in the coming sections of this article.

Bias

Bias is used to manage the space between the view and what it’s constrained to, they’re mostly used with the views that are aligned to the center.

Before going any further, you must have basic knowledge of how to work with Jetpack Compose. If you’re new to Compose, I highly recommend going through the following articles:

With that being said, let’s get started.

ConstraintLayout

ConstraintLayout is nothing but a composable function that can position its children based on the constraints specified. It also takes a modifier as an optional parameter.

ConstraintLayout {   // Childs goes here}

createRefs

createRefs is a function that provides us a convent way to create the ConstrainedLayoutReferences(nothing but layouts inside constraint layout). This function takes the leverage of destructuring declarations in Kotlin to create the required number of references.

ConstraintLayout {     val (title, subtitle, image) = createRefs()}

Here title, subtitle, and image are nothing but the views that we refer to inside the constraint layout.

constrainAs

constrainAs is nothing but an extension function on the Modifier. It has two parameters:

  1. First parameter: ConstrainedLayoutReference it’s basically used to assign the id to view, the value should be one of the references that we create via createRefs function.
  2. Second parameter: ConstrainScopenothing but a function where we specify all the constraints we want to apply to the current view/composable.
Modifier.constrainAs(subtitle) {
top.linkTo(title.bottom)
}

Let’s start from the basics, starting with how to constraint a view to its parent. Like constraining a view to center vertically, horizontally, or center to the entire screen.

Placing a view with respect to its parent

One of the new functions you encounter here is linkTo. It is nothing but a way to define a constraint using VerticalAnchorable(start and end) and HorizontalAnchorable(top and bottom).

Simple constraints ouptput

Next is to constraint a view with respect to its siblings. To explore this use case, let’s take the classic example of title, subtitle, and image.

Placing a view with respect to its parent and siblings

Box is nothing but a simple composable function, here we use a box instead of an image to keep things simple and concise. centerVerticallyTo is nothing but the utility function to add top and bottom constraints to the view sent via parameter, likewise we can also centerHorizontallyTo to add start and end constraints.

Sibling constraints output

If you see the output it’s a bit clumsy that’s because no spacing between the views and its parent. We can add margins while creating the constraints using the margin optional parameter inside linkTo function. Have a look:

start.linkTo(image.end, margin = 16.dp)
Output with margins

As said Guidelines are nothing but the invisible lines through which we can constraints the actual view in the layout. Traditionally a GuideLine can be either horizontal or vertical:

  • Vertical Guidelines with zero width and height are equal to its parent.
  • Horizontal Guidelines with zero height and width are equal to its parent.

Compose offers an extremely easy way to create guidelines via functions like createGuidelineFromStart, createGuidelineFromEnd, createGuidelineFromTop, createGuidelineFromBottom and more. Each function takes a float value as an optional parameter to align the guideline with respective to it from the direction it’s specified.

Placing a view with respect to the guidelines
guidelines code output

As I said the barrier is similar to a guideline, but the real advantage comes with multiple views scaling at runtime. In simple words using a barrier, a view can be constrained to multiple sibling views.

Similar to guidelines, compose offers a set of functions to create barriers such as: createStartBarrier, createEndBarrier, createTopBarrier, createBottomBarrier, and more. Each of these functions takes two parameters:

  1. elements: Nothing but the ConstrainedLayoutReference which we create via createRefs . The barrier will be constrained to these references. The views that depend on this barrier will change the position based on the provided references measurements.
  2. margin: Used to define the margin between the views/composables.
Placing a view with respect to the barrier
Barrier code output

As said Bias is used to manage the space between the view and what it’s constrained to, the fraction of the space to be maintained is defined as float. Here we use the following linkTo to position the view and add bias:

fun linkTo(
start: ConstraintLayoutBaseScope.VerticalAnchor,
end: ConstraintLayoutBaseScope.VerticalAnchor,
startMargin: Dp = 0.dp,
endMargin: Dp = 0.dp,
@FloatRange(from = 0.0, to = 1.0) bias: Float = 0.5f
)
  • start: Is to define the start constraint of the view
  • end: is to define the end constraint of the view.
  • Whereas startMargin and endMargin are to define the margins with the alignment.
  • bias is the fraction of the gap that we want to add to the view.
Adding bias to the views
Bias code output

That is all for now. I hope you learned something useful. Thanks for reading.

Leave a Comment