Annyce Davis

ones and zeros

  • Home
  • Public Speaking
  • About Me
  • Courses
  • Life

Programmatically laying out views in ConstraintLayout with Flow

March 17, 2021 by Annyce Davis Leave a Comment

Rotating the phone to landscape caused users of the app to experience a suboptimal experience. Turns out we had some legacy code that was manually calculating the size and position of each “chip”. 😱

Buggy Profile screen in landscape

The problem

How can we transform the following code into something that is simpler to reason on and maintain?

last == null -> {
    addView(textView, firstPillLayoutParams())
    currentLineWidth = thisWidth
    below = textView

    currentDepth += topMarginFor(textView) + textViewHeight
}

currentLineWidth + thisWidth <= actualWidth -> {
    addView(textView, sameLineLayoutParams(last))
    currentLineWidth += thisWidth
}

Enter ConstraintLayout with Flow.

The solution

In ConstraintLayout 2.0, the Flow virtual layout was introduced. If you’re unfamiliar with Flow, this blog post provides a simple introduction. The main benefits of using Flow are:

  • it supports long chains of items that can wrap to multiple rows
  • it allows you to keep your layout hierarchy flat
  • elements can be positioned vertically or horizontally

Bingo. That’s exactly what I needed.

Creating the Flow instance

We’ll start by creating the Flow instance and adding it to the ConstraintLayout. We want it to have a unique id that we can use for layout purposes. Additionally, the flow should be the same size as the parent’s width and then the height should match its contents.

val flow = Flow(context).apply {
    id = generateViewId()
    
    layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)
}
addView(flow)

At this point, each element is displayed in a row. Some of the “chips” are clipped and there’s no spacing between them. Let’s add some styling to get us closer to the desired experience.

Flow with no styling

We’ll set the wrapMode to Flow.WRAP_CHAIN. That will allows the items to wrap to additional rows. We’ll also set a few more parameters to establish the alignment of the chips in the rows. This gets us event closer to what we want.

setWrapMode(Flow.WRAP_CHAIN)
setHorizontalStyle(Flow.CHAIN_PACKED)
setHorizontalAlign(Flow.HORIZONTAL_ALIGN_START)
Flow with minor styling

Next, we set the horizontalBias to 0f so that the “chips” will start towards the left for each row instead of in the center. Then we put in gaps for both the vertical and horizontal directions.

setHorizontalBias(0f)
setVerticalGap(pillMarginWidth)
setHorizontalGap(pillMarginWidth)
setOrientation(Flow.HORIZONTAL)

Now we have just we need. A flexible layout that’s easy to reason on and looks nice in both portrait and landscape modes. šŸ‘Œ

Profile screen with use of ConstraintLayout and Flow

The complete function

Thanks for reading!

Share this:

  • Click to share on Twitter (Opens in new window)
  • Click to share on Facebook (Opens in new window)
  • Click to share on LinkedIn (Opens in new window)

Related

Filed Under: Android, Kotlin Tagged With: Android, ConstraintLayout, Flow, Kotlin

Follow Me

What engineering leaders need to know from this year’s Google I/O

I didn't intentionally aim to create a rhyming title, but there you have it. Each year, I look forward to Google I/O like a kid going back to school. This year … [Read More...]

Talk: The Real MVP

You have an idea for a new app. You've secured buy-in from the business. What's next? The MVP. But what does it take to ship a new app these days? What are the … [Read More...]

Categories

  • Android (55)
  • Career (2)
  • Communication (4)
  • Flutter (1)
  • Git (4)
  • Gradle (4)
  • Grails (23)
  • Java (8)
  • JavaScript (6)
  • Kotlin (17)
  • Life (4)
  • Public Speaking (23)
  • RxJava (1)
  • Software Development (7)
  • Twitter (3)
  • Uncategorized (11)
  • Video Course (5)

Copyright © 2023 · Beautiful Pro Theme on Genesis Framework · WordPress · Log in

 

Loading Comments...