Lazy Grid Layouts in Jetpack Compose (with Examples)

Jetpack Compose Lazy Grid Layout

In this article, we’ll learn how to implement lazy grid layouts in Android Jetpack Compose.

Prerequisites:

What are Lazy Grid Layouts in Jetpack Compose?

Lazy grid layouts are used to display items in a grid. They only render the items that are currently visible on the screen. As a result, they are memory efficient for displaying a large set of data, such as images from a gallery.

For this article, create an empty Jetpack Compose project and open MainActivity.kt. Create a composable called MyUI() and call it from the onCreate().

// we need the following packages
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.LazyHorizontalGrid
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            YourProjectNameTheme(darkTheme = false) {
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colors.background
                ) {
                    Column(
                        modifier = Modifier.fillMaxSize()
                    ) {
                        MyUI()
                    }
                }
            }
        }
    }
}

@Composable
fun MyUI() {
   
}

We’ll write our code in the MyUI().

Jetpack Compose provides two lazy grid APIs:

  1. LazyVerticalGrid
  2. LazyHorizontalGrid

1. Lazy Vertical Grid Example:

It displays a vertically scrolling grid. The API looks like this:

@Composable
fun LazyVerticalGrid(
    columns: GridCells,
    modifier: Modifier = Modifier,
    state: LazyGridState = rememberLazyGridState(),
    contentPadding: PaddingValues = PaddingValues(0.dp),
    reverseLayout: Boolean = false,
    verticalArrangement: Arrangement.Vertical =
        if (!reverseLayout) Arrangement.Top else Arrangement.Bottom,
    horizontalArrangement: Arrangement.Horizontal = Arrangement.Start,
    flingBehavior: FlingBehavior = ScrollableDefaults.flingBehavior(),
    userScrollEnabled: Boolean = true,
    content: LazyGridScope.() -> Unit
)

columns – Number of columns of the grid. Instead of a number, we can also set the minimum size for each item.

modifierThe modifier to apply to this layout.

stateThe state of the list.

contentPadding – It adds a margin around the whole content.

reverseLayout – Reverse the direction of scrolling and layout.

verticalArrangement – The vertical arrangement of the layout’s children.

horizontalArrangement – The horizontal arrangement of the layout’s children.

flingBehavior – Logic describing the fling behavior.

userScrollEnabled – Whether scrolling via the user gestures or accessibility actions is allowed. You can still scroll programmatically using the state even when it is disabled.

content – The content of the list. We add items (children) here.

The number of columns depends on the columns parameter. There are two options – Fixed and Adaptive.

Fixed Columns:

We use GridCells.Fixed() class to create a grid with fixed number of columns.

class Fixed(private val count: Int) : GridCells {}

The count parameter determines the number of columns. For example, if count = 5, there will be five columns. Each column will have a width of 1/5th of the parent’s width.

For example, if the parent’s width is 100 pixels, each column will have a width of 20 pixels. The columns will be evenly distributed.

Adaptive Columns:

We use GridCells.Adaptive() class to create a grid with adaptive size.

class Adaptive(private val minSize: Dp) : GridCells {}

It creates as many columns as possible with the condition that each column has at least minSize width. All the columns have equal width.

For example, if minSize = 20.dp, there will be as many columns as possible, and every column has a width of at least 20.dp. If the screen is 88.dp wide, there will be four columns with 22.dp each.

Simple Lazy Vertical Grid Example:

The columns and content parameters are mandatory.

@Composable
fun MyUI() {
    LazyVerticalGrid(
        modifier = Modifier.fillMaxSize(),
        columns = GridCells.Fixed(count = 4)
    ) {
        items(count = 100) { index ->
            Box(
                modifier = Modifier
                    .fillMaxWidth()
                    .height(height = 100.dp)
                    .background(color = Color.Magenta, shape = RoundedCornerShape(size = 4.dp)),
                contentAlignment = Alignment.Center
            ) {
                Text(
                    text = "$index",
                    color = Color.White,
                    fontWeight = FontWeight.Bold
                )
            }
        }
    }
}

Output:

Lazy Vertical Grid Example

The output doesn’t look good because children don’t have a margin. Let’s add some margin to improve the appearance.

Margin/Padding Between Children:

There are three parameters to add padding – verticalArrangement, horizontalArrangement, and contentPadding.

verticalArrangement – Adds top and bottom margin between each item.

horizontalArrangement – Adds left and right margin between each item.

contentPadding – Adds margin to the whole layout.

@Composable
fun MyUI() {
    LazyVerticalGrid(
        modifier = Modifier.fillMaxSize(),
        columns = GridCells.Fixed(count = 4),
        verticalArrangement = Arrangement.spacedBy(space = 16.dp), // top and bottom margin between each item
        horizontalArrangement = Arrangement.spacedBy(space = 16.dp), // left and right margin between each item
        contentPadding = PaddingValues(all = 10.dp) // margin for the whole layout
    ) {
        items(count = 100) { index ->
            Box(
                modifier = Modifier
                    .fillMaxWidth()
                    .height(height = 100.dp)
                    .background(color = Color.Magenta, shape = RoundedCornerShape(size = 4.dp)),
                contentAlignment = Alignment.Center
            ) {
                Text(
                    text = "$index",
                    color = Color.White,
                    fontWeight = FontWeight.Bold
                )
            }
        }
    }
}

Output:

Margin or Padding Between Children

Lazy Vertical Grid Adaptive Size:

Instead of a fixed size, let’s create a grid with an adaptive number of columns.

@Composable
fun MyUI() {
    LazyVerticalGrid(
        modifier = Modifier.fillMaxSize(),
        columns = GridCells.Adaptive(minSize = 100.dp), // adaptive size
        verticalArrangement = Arrangement.spacedBy(space = 16.dp),
        horizontalArrangement = Arrangement.spacedBy(space = 16.dp),
        contentPadding = PaddingValues(all = 10.dp)
    ) {
        items(count = 100) { index ->
            Box(
                modifier = Modifier
                    .fillMaxWidth()
                    .height(height = 100.dp)
                    .background(color = Color.Magenta, shape = RoundedCornerShape(size = 4.dp)),
                contentAlignment = Alignment.Center
            ) {
                Text(
                    text = "$index",
                    color = Color.White,
                    fontWeight = FontWeight.Bold
                )
            }
        }
    }
}

Output:

Adaptive Size

2. Lazy Horizontal Grid:

It creates a horizontally scrollable list.

fun LazyHorizontalGrid(
    rows: GridCells,
    modifier: Modifier = Modifier,
    state: LazyGridState = rememberLazyGridState(),
    contentPadding: PaddingValues = PaddingValues(0.dp),
    reverseLayout: Boolean = false,
    horizontalArrangement: Arrangement.Horizontal =
        if (!reverseLayout) Arrangement.Start else Arrangement.End,
    verticalArrangement: Arrangement.Vertical = Arrangement.Top,
    flingBehavior: FlingBehavior = ScrollableDefaults.flingBehavior(),
    userScrollEnabled: Boolean = true,
    content: LazyGridScope.() -> Unit
)

The parameters are similar to LazyVerticalGrid.

Simple Lazy Horizontal Grid Example:

The rows and content parameters are mandatory.

@Composable
fun MyUI() {
    LazyHorizontalGrid(
        modifier = Modifier.fillMaxSize(),
        rows = GridCells.Fixed(count = 4),
        verticalArrangement = Arrangement.spacedBy(space = 16.dp), // top and bottom margin for each item
        horizontalArrangement = Arrangement.spacedBy(space = 16.dp), // left and right margin for each item
        contentPadding = PaddingValues(all = 10.dp) // margin for the whole layout
    ) {
        items(count = 100) { index ->
            Box(
                modifier = Modifier
                    .fillMaxHeight()
                    .width(width = 100.dp)
                    .background(color = Color.Magenta, shape = RoundedCornerShape(size = 4.dp)),
                contentAlignment = Alignment.Center
            ) {
                Text(
                    text = "$index",
                    color = Color.White,
                    fontWeight = FontWeight.Bold
                )
            }
        }
    }
}

Output:

Lazy Horizontal Grid Example

Adaptive Size:

To set the adaptive size, use the same GridCells.Adaptive() method.

@Composable
fun MyUI() {
    LazyHorizontalGrid(
        modifier = Modifier.fillMaxSize(),
        rows = GridCells.Adaptive(minSize = 80.dp), // adaptive size
        verticalArrangement = Arrangement.spacedBy(space = 16.dp),
        horizontalArrangement = Arrangement.spacedBy(space = 16.dp),
        contentPadding = PaddingValues(all = 10.dp)
    ) {
        items(count = 100) { index ->
            Box(
                modifier = Modifier
                    .fillMaxHeight()
                    .width(width = 100.dp)
                    .background(color = Color.Magenta, shape = RoundedCornerShape(size = 4.dp)),
                contentAlignment = Alignment.Center
            ) {
                Text(
                    text = "$index",
                    color = Color.White,
                    fontWeight = FontWeight.Bold
                )
            }
        }
    }
}

Output:

Adaptive Size

This is all about lazy grid layouts in Jetpack Compose. I hope you have learned something new. If you have any doubts, leave a comment below.

Related Posts:

References:

Leave a Comment