Instruction

Jetpack Compose offers four variants of grids out of the box:

  • LazyVerticalGrid: Creates a vertically scrolling grid.
  • LazyHorizontalGrid: Creates a horizontally scrolling grid.
  • LazyVerticalStaggeredGrid: Creates a vertically scrolling staggered grid.
  • LazyHorizontalStaggeredGrid: Creates a horizontally scrolling staggered grid.

You’ll go over each of these one by one.

Exploring Grids in Jetpack Compose

When building standard grid UIs in Jetpack Compose, you can opt for LazyVerticalGrid and LazyHorizontalGrid, both of which allow you to display items in a grid.

LazyVerticalGrid lets you display grids with items spanning multiple columns in a vertically scrollable container, while LazyHorizontalGrid does the same on the horizontal axis.

Let’s look at the signatures of LazyVerticalGrid and LazyHorizontalGrid:

@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  
)


@Composable  
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  
)

If you look closely, these composables look very similar. Both accept an arrangement parameter based on their respective scroll orientations, and both grid variants accept a content parameter representing the grid’s content.

Just like regular lists, these use a DSL from LazyGridScope. LazyGridScope plays the role of the receiver scope in these grid composables.

@LazyGridScopeMarker  
sealed interface LazyGridScope {

  fun item(  
      key: Any? = null,  
      span: (LazyGridItemSpanScope.() -> GridItemSpan)? = null,  
      contentType: Any? = null,  
      content: @Composable LazyGridItemScope.() -> Unit  
  )

  fun items(  
      count: Int,  
      key: ((index: Int) -> Any)? = null,  
      span: (LazyGridItemSpanScope.(index: Int) -> GridItemSpan)? = null,  
      contentType: (index: Int) -> Any? = { null },  
      itemContent: @Composable LazyGridItemScope.(index: Int) -> Unit 
  )

}

Here’s a breakdown of the snippet above

  • The item() receiver lets you add a single item to the grid. You may use item() as many times as you want to add multiple items.

  • If you need to add an entire collection of items to the grid, use items() instead. Items accept a count parameter that represents the count of the items being added and a key to uniquely identify each item in the grid.

Note: The key parameter in the items receiver must be a constant that is unique for each item. This is so the runtime can uniquely identify each item in the list and perform partial updates to it in case the backing data changes. The key is also used to maintain the scroll position on the screen and handle adding or removing items from the screen.

Using LazyVerticalGrid and LazyHorizontalGrid

You can use a LazyVerticalGrid as in the following example:

LazyVerticalGrid(
  columns = GridCells.Adaptive(minSize = 100.dp)) {
     items(items = photos) { photo ->        
         PhotoItem(photo)    
    }  
}

In the example above, you:

  • Created a LazyVerticalGrid.
  • Used the items() extension function that calculates the count and the key values for you.
  • Specified the column configuration using GridCells.Adaptive, with each column spanning a minimum width of 100dp.
  • Passed a list of photos to the items receiver and rendered a PhotoItem for each photo.

Note: You may also use GridCells.Fixed to create fixed columns that won’t adapt to the screen width.

Using the LazyHorizontalGrid is quite similar to LazyVerticalGrid:

LazyHorizontalGrid(
  rows = GridCells.Adaptive(minSize = 50.dp)) {
     items(items = testimonials) { testimonial ->        
         TestimonialCard(testimonial)    
    }  
}

In the example above, you :

  • Created a LazyHorizontalGrid.
  • Specified the row configuration using GridCells.Adaptive, with each row spanning a minimum width of 50dp.
  • Used the items() extension function that calculates the count and the key values for you.
  • Passed a list of testimonials to the items receiver and rendered a TestimonialCard for each testimonial.

Exploring Staggered Grids in Jetpack Compose

A staggered grid is one in which items are arranged non-uniformly across their respective axes. Such grids can prove helpful when rendering items with non-uniform width and height, like a collection of photos.

In Jetpack Compose, you can use LazyVerticalStaggeredGrid and LazyHorizontalStaggeredGrid to render staggered grids.

Here’s a look at their signatures:

@Composable  
fun LazyVerticalStaggeredGrid(  
    columns: StaggeredGridCells,  
    modifier: Modifier = Modifier,  
    state: LazyStaggeredGridState = rememberLazyStaggeredGridState(),  
    contentPadding: PaddingValues = PaddingValues(0.dp),  
    reverseLayout: Boolean = false,  
    verticalItemSpacing: Dp = 0.dp,  
    horizontalArrangement: Arrangement.Horizontal = Arrangement.spacedBy(0.dp),  
    flingBehavior: FlingBehavior = ScrollableDefaults.flingBehavior(),  
    userScrollEnabled: Boolean = true,  
    content: LazyStaggeredGridScope.() -> Unit  
)


@Composable  
fun LazyHorizontalStaggeredGrid(  
    rows: StaggeredGridCells,  
    modifier: Modifier = Modifier,  
    state: LazyStaggeredGridState = rememberLazyStaggeredGridState(),  
    contentPadding: PaddingValues = PaddingValues(0.dp),  
    reverseLayout: Boolean = false,  
    verticalArrangement: Arrangement.Vertical = Arrangement.spacedBy(0.dp),  
    horizontalItemSpacing: Dp = 0.dp,  
    flingBehavior: FlingBehavior = ScrollableDefaults.flingBehavior(),  
    userScrollEnabled: Boolean = true,  
    content: LazyStaggeredGridScope.() -> Unit  
)

Both the LazyVerticalStaggeredGrid and LazyHorizontalStaggeredGrid accept instances of StaggeredGridCells as row or column arguments. They accept verticalItemSpacing and horizontalItemSpacing to stagger the item placement horizontally and vertically, along with a LazyStaggeredGridScope instance representing the staggered grid’s content.

Using LazyVerticalStaggeredGrid and LazyHorizontalStaggeredGrid

You can use a LazyVerticalStaggeredGrid as in the following example:

LazyVerticalStaggeredGrid(  
    modifier = Modifier.fillMaxSize(),  
    columns = StaggeredGridCells.Adaptive(200.dp),  
    verticalItemSpacing = 4.dp,  
    horizontalArrangement = Arrangement.spacedBy(4.dp),  
    content = {  
        items(randomSizedPhotos) { photo ->  
            PhotoItem(photo)  
        }  
    }
)

In the example above, you:

  • Created a LazyVerticalStaggeredGrid.
  • Used the fillMaxSize modifier to ensure it spans the entire width and height of the screen.
  • Specified the column configuration using StaggeredGridCells.Adaptive, with each column spanning a minimum width of 200dp.
  • Specified the verticalItemSpacing to space each item 4dp apart vertically.
  • Specified the horizontalArrangement to space each item 4dp apart horizontally.
  • Passed a list of random-size photos to the items receiver and rendered a PhotoItem for each photo.

The verticalItemSpacing parameter controls the spacing between each row of the grid, thereby creating space between items vertically within the grid. In contrast, the horizontalArrangement property determines how each item in a row is arranged horizontally and the space between each item.

Note: You may also use the StaggeredGridCells.Fixed to create fixed columns that won’t adapt to the screen width.

See forum comments
Download course materials from Github
Previous: Introduction Next: Demo