Layouts

Organization slay

As you may recall from Native Android, UI elements live in a hierarchy, where each element has a parent element by which it is contained. Jetpack Compose allows us to create this hierarchy by calling other composable functions inside the one we are creating. However, if you try just putting two Text composables right after one another, you will notice that they will overlap and make the text unreadable. Therefore, we need some ways to organize the composables to our liking.

Jetpack Compose provides multiple methods to arrange multiple composable functions depending on the format the user wants. The most common ones are Rows, Columns, and Boxes. As the names suggest, Rows allow us to put composables in a row with one another, while Columns allow us to put composables in a column with one another. Boxes may seem a bit more unintuitive, but they allow us to arrange the composables inside of it however we like, including overlapping composables, which Rows and Columns do not allow.

Another thing to note is that while in Native Android, we want to avoid nested layouts because it slows down runtime, Jetpack Compose has optimized for layouts and therefore the performance will not be impeded by nested layouts.

Alignment and Arrangement

When we want to manage the layout of items within a Row or Column, there are some arguments that we can specify in order to do so. For example, as you can see below, we can use the verticalAlignment and horizontalArrangement arguments in order to specify that we want the composables inside the Row to be centered vertically and right-aligned (using Arrangement.End). Similarly, Columns have horizontalAlignment and verticalArrangement arguments to specify how the composables inside should be arranged.

@Composable
fun ArtistCard(artist: Artist) {
    Row(
        verticalAlignment = Alignment.CenterVertically,
        horizontalArrangement = Arrangement.End
    ) {
        Image(/*...*/)
        Text { /*...*/ }
    }
}

Here's a list of Arrangements and Alignments from a website discussing the intricacies of Jetpack Compose Layouts that may come in handy:

  • Arrangement.Start: places items in the main axis start.

  • Arrangement.End: places items in the main axis end.

  • Arrangement.Center: places items in the main axis center.

  • Arrangement.SpaceBetween: places first item in the main axis start and the last item in the main axis end, then distributes the remaining items evenly in the space left.

  • Arrangement.SpaceAround: puts the same amount of space on the left and the right of each item (in a Row, or top and bottom in a Column). Notice that spaces in the middle will be twice as large as spaces in the ends.

  • Arrangement.SpaceEvenly: puts the same amount of space between items, the start and the end. It differentiates from space around because the spacing at the start and end is the same as the spacing in the middle.

When using a Box, the composables inside of it will have padding from the boundaries of it. Therefore, we can allow multiple composables to overlap simply by adjusting their paddings to make them in similar places. Here's an example from the Scooped profile screen:

Box(
    modifier = Modifier.fillMaxSize(),
) {
    Image(/*...*/)
    Column {
        Spacer(
            modifier = Modifier
                .height(133.dp)
                .fillMaxWidth()
        )
        /*...*/
    }
    Image(
        painter = /*...*/,
        contentDescription = null,
        modifier = Modifier
            .padding(top = 68.dp)
            .size(128.dp)
            .clip(CircleShape)
            .align(Alignment.TopCenter)
            .border(width = 3.dp, color = Green, shape = CircleShape)
    )
}

Also, you may notice that we have a modifier inside the Image referencing Alignment.TopCenter. The reason that we're able to do this is that we are able to use either the contentAlignment argument for the Box itself or we can use the modifier.align() method on the children of the Box.

Last updated