Reputation: 6663
I have a LazyVerticalGrid with 2 cells.
LazyVerticalGrid(
cells = GridCells.Fixed(2),
content = {
items(moviePagingItems.itemCount) { index ->
val movie = moviePagingItems[index] ?: return@items
MovieItem(movie, Modifier.preferredHeight(320.dp))
}
renderLoading(moviePagingItems.loadState)
}
)
I am trying to show full width loading with LazyGridScope
's fillParentMaxSize
modifier.
fun LazyGridScope.renderLoading(loadState: CombinedLoadStates) {
when {
loadState.refresh is LoadState.Loading -> {
item {
LoadingColumn("Fetching movies", Modifier.fillParentMaxSize())
}
}
loadState.append is LoadState.Loading -> {
item {
LoadingRow(title = "Fetching more movies")
}
}
}
}
But since we have 2 cells, the loading can occupy half of the screen. Like this:
Is there a way my loading view can occupy full width?
Upvotes: 20
Views: 18586
Reputation: 31
I have designed a user interface where I want to display cards in a single cell for "Type A" and in double cells for "Type B". I was able to achieve this using the span attribute in items.
However, I recently discovered that LazyVerticalGrid already has a span strategy built into items() and itemsIndexed().
Here's a sample code snippet:
@Composable
internal fun SearchSlimCardContent(activityGroup: List<ActivityGroup?>) {
val screenHeight = LocalConfiguration.current.screenHeightDp
val list = activityGroup.flatMap { group ->
group?.activityTiles ?: emptyList()
}
Column(modifier = Modifier.height(screenHeight.dp)) {
LazyVerticalGrid(
columns = GridCells.Fixed(2),
modifier = Modifier.padding(4.dp)
) {
items(list, span = { tile ->
val span = if (tile.__typename == "Type A") {
2
} else {
1
}
GridItemSpan(span)
}
) { tiles ->
when (tiles.__typename) {
"Type A" ->
ActivitySearchBanner(
activityMessagingTile = tiles.fragments.activityMessagingTile
)
"Type B" ->
ActivitySlimCardTile(
activityTile = tiles.fragments.activityTile
)
else -> {}
}
}
}
}
Upvotes: 1
Reputation: 4375
LazyVerticalGrid
has a span strategy built into items()
and itemsIndexed()
@Composable
fun SpanLazyVerticalGrid(cols: Int, itemList: List<String>) {
val lazyGridState = rememberLazyGridState()
LazyVerticalGrid(
columns = GridCells.Fixed(cols),
state = lazyGridState
) {
items(itemList, span = { item ->
val lowercase = item.lowercase()
val span = if (lowercase.startsWith("a") || lowercase.lowercase().startsWith("b") || lowercase.lowercase().startsWith("d")) {
cols
}
else {
1
}
GridItemSpan(span)
}) { item ->
Box(modifier = Modifier
.fillMaxWidth()
.height(150.dp)
.padding(10.dp)
.background(Color.Black)
.padding(2.dp)
.background(Color.White)
) {
Text(
modifier = Modifier.align(Alignment.Center),
text = item,
fontSize = 18.sp
)
}
}
}
}
'
val names = listOf("Alice", "Bob", "Cindy", "Doug", "Ernie", "Fred", "George", "Harris")
SpanLazyVerticalGrid(
cols = 3,
itemList = names
)
Upvotes: 13
Reputation: 6663
Jetpack Compose 1.1.0-beta03
version includes horizontal span support for LazyVerticalGrid
.
Here is the example usage:
private const val CELL_COUNT = 2
private val span: (LazyGridItemSpanScope) -> GridItemSpan = { GridItemSpan(CELL_COUNT) }
LazyVerticalGrid(
cells = GridCells.Fixed(CELL_COUNT),
content = {
items(moviePagingItems.itemCount) { index ->
val movie = moviePagingItems.peek(index) ?: return@items
Movie(movie)
}
renderLoading(moviePagingItems.loadState)
}
}
private fun LazyGridScope.renderLoading(loadState: CombinedLoadStates) {
if (loadState.append !is LoadState.Loading) return
item(span = span) {
val title = stringResource(R.string.fetching_more_movies)
LoadingRow(title = title)
}
}
Code examples of this answer can be found at: Jetflix/MoviesGrid.kt
Upvotes: 15
Reputation: 1297
Try something like:
var cellState by remember { mutableStateOf(2) }
LazyVerticalGrid(
cells = GridCells.Fixed(cellState),
content = {
items(moviePagingItems.itemCount) { index ->
val movie = moviePagingItems[index] ?: return@items
MovieItem(movie, Modifier.preferredHeight(320.dp))
}
renderLoading(moviePagingItems.loadState) {
cellState = it
}
}
)
The renderLoading
function:
fun LazyGridScope.renderLoading(loadState: CombinedLoadStates, span: (Int) -> Unit) {
when {
loadState.refresh is LoadState.Loading -> {
item {
LoadingColumn("Fetching movies", Modifier.fillParentMaxSize())
}
span(1)
}
...
else -> span(2)
}
}
Upvotes: 2
Reputation: 6616
I have created an issue for it: https://issuetracker.google.com/u/1/issues/176758183
Current workaround I have is to use LazyColumn
and implement items or header.
override val content: @Composable () -> Unit = {
LazyColumn(
contentPadding = PaddingValues(8.dp),
content = {
items(colors.chunked(3), itemContent = {
Row(horizontalArrangement = Arrangement.SpaceEvenly) {
val modifier = Modifier.weight(1f)
it.forEach {
ColorItem(modifier, it)
}
for (i in 1..(3 - it.size)) {
Spacer(modifier)
}
}
})
item {
Text(
text = stringResource(R.string.themed_colors),
style = MaterialTheme.typography.h3
)
}
items(themedColors.chunked(3), itemContent = {
Row(horizontalArrangement = Arrangement.SpaceEvenly) {
val modifier = Modifier.weight(1f)
it.forEach {
ColorItem(modifier, it)
}
for (i in 1..(3 - it.size)) {
Spacer(modifier)
}
}
})
})
}
Upvotes: 1