Jetpack Compose — Drawer Pushing Content

Hello.

This is my first story on this kind of themes, but I hope I can catch your attention anyway.

So, since the Android team released Jetpack Compose first beta version, I’ve been trying my best to keep in sync with all the updates, by following the Android Dev Challenges and also by trying to reproduce my projects with it.

One of the things that I wanted to do, was to have the famous Drawer Layout, but instead of overlaying the screen content, have it pushing the screen content with it.

Following their awesome documentation about Layouts in Compose, I found that using Compose, creating custom layouts, with custom specs has become really easy.

“To measure and layout multiple composables, use the Layout composable instead. This composable allows you to measure and lay out children manually. All higher-level layouts like Column and Row are built with the Layout composable.”

I knew I had to start from here, since I will have definitely to main composables to measure:

  • The drawer layout
  • The screen content

Below is an example of a custom Column layout:

By analyzing it, we can see that a Layout composable is created.

In this article I won’t be covering in depth the Layout composable, but we can see that the last argument is a lambda, which gives us two things to work with:

  • “measurables”
  • “constraints”

Measurables:

“A part of the composition that can be measured. This represents a layout.”

Constraints:

Immutable constraints used for measuring layouts, usually as part of parent layouts or layout modifiers. Children layouts can be measured using the measure method on the corresponding Measurables.”

The first piece of code, goes though each measurable, and transforms each one in its measure.

The last piece of code sets the parent layout width and height, and then goes through each placeable (child) and places it in the corresponding x and y positions. In order to make it work as a vertical orientation column, it keeps track of the y position, and keeps incrementing it by the child height on each loop.

Ok, now, let’s speak about the drawer.

The DrawerContainer composable receives as arguments:

  • modifier, which is used to decorate or add behaviours to the layout
  • isDrawerOpened, which determines if the drawer should be open or not
  • drawerWidth, which corresponds to the width in Dp of the drawer
  • onSwipe, which is a lambda that has as an argument if the drawer should be open or not, based on the dragAmount being positive or not
  • content, which is the children layouts

Here I make use of Jetpack Compose Animation.

Since I want the drawer state (open or closed) to be decided upon isDrawerOpened value, I use updateTransition function, with the targetState being isDrawerOpened. This means that every time that value changes, the transitions will run.

The collapseFraction, will be changing whenever the isDrawerOpened changes, from 0f (0%) if false, to 1f (100%) if true.

After setting up the collapsingFraction, I create my Layout composable, but in this case I’ll change its modifier, to include the function pointerInput, where I implement the method detectHorizontalDragGestures, which has a last argument of a lambda, where we can check the current dragAmount. If the transition is not already running, I’ll send the callback informing if it was swiped to open or to close, based on the dragAmount.

Then, inside the Layout composable, I start by measuring both the drawer measurable, and the screen content measurable. Note that when measuring the drawer, I pass drawerWidth.roundToPx() as the width, which is the argument of our DrawerContainer composable.

To decide what should be drawerX and the contentX, I use the function MathUtils.lerp, which will going from the start value to the end value, based on the collapseFraction value (0f to 1f). Note that this X values, correspond to the top left corner of both layouts.

To finalize, I set the parent layout width and height based on the constraints, and I place both layouts on the correct places.

Then.. how to use it:

Congratulations if you’ve reached the final of the article, and I hope you have enjoyed it. I accept any kind of suggestion to get better at writing these.

If you enjoyed it, and if this helped you, you can also consider paying me a coffee. :]

Thank you!

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store