Exploring Jetpack Compose: FlexColumn & FlexRow

E

In the last article we looked at both the Row and Column layouts, along with how they can be used when constructing our user interface. Alongside these Row and Column components we also have the FlexRow and FlexColumn components – which are both very similar. With the FlexRow and FlexColumn we have addition of declaring child component weights to depict how they are to be laid out inside of the corresponding parent container – similar to how we may have be using weights with linear layouts.

In the case of the FlexRow and FlexColumn, each child of these is one of three type – this type depicts how the child is to be laid out inside of its parent. These types are:

  • Inflexible – this states that the child is not flex, meaning that it will only take as much space as it is needed. For this reason, inflexible children will be measured first before both Flexible and Expanded children
  • Expanded – this states that the child will be expanded to fill any remaining space within it’s parent, relative to the flex weight assigned to it and the other children within the parent component
  • Flexible – similar to the behaviour of an expanded child, except for the fact that the child will not expand to fill all available height – meaning that unoccupied space may be left within the parent component

We can take a quick look at these in action to demonstrate how they work within a project. For example, let’s take a fixe size container and add three inflexible child components to the column:

FlexColumn(
    modifier = Size(width = 200.dp, height = 100.dp)
) {
    inflexible {
        Text("One", style = TextStyle(color = Color.White))
    }
    inflexible {
        Text("Two", style = TextStyle(color = Color.White))
    }
    inflexible {
        Text("Three", style = TextStyle(color = Color.White))
    }
}

We can see here that each of the child takes up only the space that they need and do not expand to fill any of the remaining space within the parent container. This also leaves us with a large amount of unused empty space at the bottom of the column, due to the face out child components have not been expanded.

On the other hand we also have the expanded state. With this we still provide the child component like we do within inflexible, however here we are also required to provide the flex (weighting) of the component. Let’s take the below example:

FlexColumn(
    modifier = Size(width = 200.dp, height = 100.dp)
) {
    expanded(flex = 2f, children = {
        Text("One", style = TextStyle(color = Color.White))
    })
    expanded(flex = 1f, children = {
        Text("Two", style = TextStyle(color = Color.White))
    })
    expanded(flex = 1f, children = {
        Text("Three", style = TextStyle(color = Color.White))
    })
}

Here we can see that the first child component has a greater flex than the following ones. With this in mind, this means that more space of the parent container is more given to the child component with that greater weight and then distributed evenly between the remained too components (as they share the same flex of 1).

In the case where we might want to distribute all of the available space evenly between each of the child components, we can give each of the children from above a matching flex of 1. This gives us the result of something like this:

Whilst expanded allows us to declare that our child components should stretch to fill the available space of a component, we might not always want that to be the case. For example, we may have a text component that if stretched may for some reason look unaligned within its container. For this (or for any other reason!) we may want to still have child components consume available space but not actually expand to fill it. This is where the flexible state comes into play.

As mentioned at the start of this post, the flexible state declares that space within the parent will be allocated to the given child component, but the child will not expand to fill that given space – so the space is still occupied and unavailable to other child components. Let’s take the below example to begin with – each child here as the same flex value and given the same amount of space within the parent container

FlexColumn(
            modifier = androidx.ui.layout.Size(width = 200.dp, height = 100.dp)
        ) {
            expanded(flex = 2f, children = {
                Text("One", style = TextStyle(color = Color.White))
            })
            flexible(flex = 2f, children = {
                Text("Two", style = TextStyle(color = Color.White))
            })
            expanded(flex = 2f, children = {
                Text("Three", style = TextStyle(color = Color.White))
            })
        }

We can see here that our first and last child have both been expanded to take up the space that matches their flex. However, for our second child we can see that it hasn’t quite expanded to fill the flex, even though it has the same flex value. This is because we are using the flexible type which means that whilst space is allocated for that child (which is the leftover space seen below the last child within our FlexColumn), the space is not used by the child itself.

To demonstrate this further, let’s bump the flex of our flexible type to 8:

flexible(8f, children = {
    Text("Two", style = TextStyle(color = Color.White))
})

As we can see here, even more space is now taken up from this flex again not actually used by the child component itself but still taken into account when the child sizings are calculated.

On the other hand, we may still only want a child component to take up the space it needs but instead have the remaining space used by the other child components. In these cases we can switch our flexible type for an inflexible type, as we can see below our first and third child components here now take up the remaining space inside of our FlexColumn.

inflexible {
    Text("Two", style = TextStyle(color = Color.White))
}

From the above examples we have been able to see how the different Flex types can be used to lay out each of our child components inside of the Flex-container. With the different combinations of these that are available, we should be able to define and display a user interface matching our requirements using these flex components.

Whilst in this post we have only covered the usage of the FlexColumn, the rules for FlexRow are exactly the same – the only difference is the content being laid out in a row format. If you have any questions on how the FlexColumn / FlexRow work, please feel free to reach out!

About the author

hitherejoe

Add Comment

By hitherejoe