Center loading indicator at the bottom of LazyVerticalGrid - android

I have implemented pagination in my app using jetpack compose. You can find full code here in case you need more details : https://github.com/alirezaeiii/TMDb-Compose
Here is my code :
LazyVerticalGrid(
columns = GridCells.Fixed(COLUMN_COUNT),
contentPadding = PaddingValues(
start = Dimens.GridSpacing,
end = Dimens.GridSpacing,
bottom = WindowInsets.navigationBars.getBottom(LocalDensity.current)
.toDp().dp.plus(
Dimens.GridSpacing
)
),
horizontalArrangement = Arrangement.spacedBy(
Dimens.GridSpacing,
Alignment.CenterHorizontally
),
content = {
items(lazyTMDbItems.itemCount) { index ->
val tmdbItem = lazyTMDbItems[index]
tmdbItem?.let {
TMDbItemContent(
it,
Modifier
.height(320.dp)
.padding(vertical = Dimens.GridSpacing),
onClick
)
}
}
lazyTMDbItems.apply {
when (loadState.append) {
is LoadState.Loading -> {
item(span = span) {
LoadingRow(modifier = Modifier.padding(vertical = Dimens.GridSpacing))
}
}
is LoadState.Error -> {
val message =
(loadState.append as? LoadState.Error)?.error?.message ?: return#apply
item(span = span) {
ErrorScreen(
message = message,
modifier = Modifier.padding(vertical = Dimens.GridSpacing),
refresh = { retry() })
}
}
else -> {}
}
}
})
As you see I set columns as a fix size :
columns = GridCells.Fixed(COLUMN_COUNT)
And in order to set loading indicator and error view at the bottom of Grid in the middle of screen, I have :
private val span: (LazyGridItemSpanScope) -> GridItemSpan = { GridItemSpan(COLUMN_COUNT) }
So when I use it as bellow using span for items, it will be centered :
item(span = span) {
LoadingRow(modifier = Modifier.padding(vertical = Dimens.GridSpacing))
}
My question is when columns is not a fix size. So we have :
columns = GridCells.Adaptive(minSize = 120.dp)
How can I center loading indicator and error view at the bottom of Grid in the screen? since as I understand span is working with a fix size.

You can use the LazyGridItemSpanScope.maxLineSpan value.
As reported in the doc:
The max line span (horizontal for vertical grids) an item can occupy. This will be the number of columns in vertical grids or the number of rows in horizontal grids.
For example if LazyVerticalGrid has 3 columns this value will be 3 for each cell.
LazyVerticalGrid(
columns = GridCells.Adaptive(minSize = 30.dp),
) {
items(
listgrid,
span = { index ->
GridItemSpan(maxLineSpan)
}
) {
//...
}
}

Related

How can I know the how many items will be drawn on the screen, so I can put a custom item as the last item. Without scrolling. Using Jetpack Compose

I want to show items in a grid but not scrollable. How can I know how many items I will draw on the screen based on its height and width. here i am showing only 9 items on the screen and putting the last custom item, but if I have a bigger screen, I don't know how many items will be drawn. How to solve it.
LazyVerticalGrid(
verticalArrangement = Arrangement.spacedBy(8.dp),
horizontalArrangement = Arrangement.spacedBy(8.dp),
columns = GridCells.Adaptive(120.dp)
) {
if (viewModel.state.value.participantsShown.size > 8) {
items(viewModel.state.value.participantsShown.subList(0, 8)) {
Audience(participant = it)
}
item {
OpenAllParticipants(viewModel = viewModel)
}
} else {
items(viewModel.state.value.participantsShown) {
Audience(participant = it)
}
item {
OpenAllParticipants(viewModel = viewModel)
}
I measured the available width and height and based on it I decided how many items I will draw.
BoxWithConstraints(contentAlignment = Center) {
val audienceHeight = 120.dp
val audienceWidth = 120.dp
val padd = 8.dp
val paddH = 32.dp
val col = maxWidth.div(audienceWidth + padd).toInt()
val row = maxHeight.div(audienceHeight + paddH).toInt()
println("Col $col")
println("Row $row")
val itemsToDraw = (col * row)
viewModel.state.value.itemsToDraw = itemsToDraw
LazyVerticalGrid(
verticalArrangement = Arrangement.spacedBy(8.dp),
horizontalArrangement = Arrangement.spacedBy(8.dp),
columns = GridCells.Adaptive(120.dp),
modifier = Modifier
) {
val participantsSize = viewModel.state.value.participantsShown.size
items(
viewModel.state.value.participantsShown.subList(
fromIndex = 0,
toIndex = minOf(itemsToDraw - 1, participantsSize)
)
) {
Audience(participant = it)
}
item {
OpenAllParticipants(viewModel = viewModel)
}
}
}

Make each item the same size

I've created a table from this code in my app. My problem is that when the text in one cell requires more than one line, only the one cell will resize instead of all cells in the row. This looks really ugly. I've already tried using Modifier.onSizeChanged to change the height of each other cell but it didn't work.
Code:
data class Cell(
val name: String,
val weight: Float
)
#Composable
fun RowScope.TableCell(...) { /* same as in the linked code */ }
#Composable
fun MyTable(data: List<Something>) {
val columns = listOf(
Cell("a", .25f),
Cell("b", .25f),
Cell("c", .25f),
Cell("d", .25f)
)
LazyColumn(
Modifier
.fillMaxSize()
.padding(16.dp)
) {
item {
Row {
columns.forEach {
TableCell(
text = it.name,
weight = it.weight
)
}
}
}
items(data) {
Row(Modifier.fillMaxWidth()) {
TableCell(
text = it.somenumber.toString(),
weight = columns[0].weight
)
TableCell(
text = "Abc",
weight = columns[1].weight
)
TableCell(
text = it.somestring1,
weight = columns[2].weight
)
TableCell(
text = it.somestring2,
weight = columns[3].weight
)
}
}
}
}
In such cases, you should use Modifier.height(IntrinsicSize.Min): it will override the height constraint which is set to infinity by scrollable LazyColumn. Then you can apply Modifier.fillMaxHeight to your TableCell.

Jetpack Compose Vertical Grid single item span size

In xml you can use GridLayoutManager.SpanSizeLookup in GridLayoutManager to set the span size on single items (How many columns the item will use in the row, like for example, in a grid of 3 columns I can set the first item to be span size 3 so it will use all the width of the grid), but in Compose I can't find a way to do it, the vertical grid only have a way set the global span count and add items, but not set the span size of an individual item, is there a way to do it?
Jetpack Compose version 1.1.0-beta03 introduced horizontal spans to LazyVerticalGrid.
Example code:
val list by remember { mutableStateOf(listOf("A", "E", "I", "O", "U")) }
LazyVerticalGrid(
cells = GridCells.Fixed(2)
) {
// Spanned Item:
item(
span = {
// Replace "maxCurrentLineSpan" with the number of spans this item should take.
// Use "maxCurrentLineSpan" if you want to take full width.
GridItemSpan(maxCurrentLineSpan)
}
) {
Text("Vowels")
}
// Other items:
items(list) { item ->
Text(item)
}
}
There is no support for this out of the box at present. The way I have solved this for now is to use a LazyColumn then the items are Rows and in each Row you can decide how wide an item is, using weight.
I have implemented and in my case I have headers (full width), and cells of items of equal width (based on how wide the screen is, there could be 1, 2 or 3 cells per row). It's a workaround, but until there is native support from VerticalGrid this is an option.
My solution is here - look for the LazyListScope extensions.
Edit: this is no longer necessary as LazyVerticalGrid supports spans now, here's an example
LazyVerticalGrid(
columns = GridCells.Adaptive(
minSize = WeatherCardWidth,
),
modifier = modifier,
contentPadding = PaddingValues(all = MarginDouble),
horizontalArrangement = Arrangement.spacedBy(MarginDouble),
verticalArrangement = Arrangement.spacedBy(MarginDouble),
) {
state.forecastItems.forEach { dayForecast ->
item(
key = dayForecast.header.id,
span = { GridItemSpan(maxLineSpan) }
) {
ForecastHeader(
state = dayForecast.header,
modifier = Modifier
.fillMaxWidth()
.padding(vertical = MarginDouble),
)
}
items(
items = dayForecast.forecast,
key = { hourForecast -> hourForecast.id }
) { hourForecast ->
ForecastWeatherCard(
state = hourForecast,
modifier = Modifier.fillMaxWidth(),
)
}
}
}
Adapting the code from the answer, I created a more "general" purpose method, It can be used with Adaptive and Fixed, I'm very new with Compose so I accept suggestions
#Composable
fun HeaderGrid(cells: GridCells, content: HeaderGridScope.() -> Unit) {
var columns = 1
var minColumnWidth = 0.dp
when (cells) {
is GridCells.Fixed -> {
columns = cells.count
minColumnWidth = cells.minSize
}
is GridCells.Adaptive -> {
val width = LocalContext.current.resources.displayMetrics.widthPixels
val columnWidthPx = with(LocalDensity.current) { cells.minSize.toPx() }
minColumnWidth = cells.minSize
columns = ((width / columnWidthPx).toInt()).coerceAtLeast(1)
}
}
LazyColumn(modifier = Modifier.fillMaxWidth()){
content(HeaderGridScope(columns, minColumnWidth, this))
}
}
fun <T>HeaderGridScope.gridItems(items: List<T>, content: #Composable (T) -> Unit) {
items.chunked(numColumn).forEach {
listScope.item {
Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceEvenly) {
it.forEach {
content(it)
}
if (it.size < numColumn) {
repeat(numColumn - it.size) {
Spacer(modifier = Modifier.width(columnWidth))
}
}
}
}
}
}
fun HeaderGridScope.header(content: #Composable BoxScope.() -> Unit) {
listScope.item {
Box(
modifier = Modifier
.fillMaxWidth(),
content = content
)
}
}
data class HeaderGridScope(val numColumn: Int, val columnWidth: Dp, val listScope: LazyListScope)
sealed class GridCells {
class Fixed(val count: Int, val minSize: Dp) : GridCells()
class Adaptive(val minSize: Dp) : GridCells()
}

How can I create a table in Jetpack Compose?

I want to create table views, like the one below, to show the data I have.
A header
Another header
First
row
Second
row
I tried using LazyVerticalGrid to achieve it but Jetpack Compose doesn’t allow me to put LazyVerticalGrid inside a vertically scrollable Column.
It’s been two days and I’m really out of idea. Please help.
As far as I know, there's no built-in component to that. But it's actually easy to do it with LazyColumn and using the same weight for all lines of the same column.
See this example:
First, you can define a cell for your table:
#Composable
fun RowScope.TableCell(
text: String,
weight: Float
) {
Text(
text = text,
Modifier
.border(1.dp, Color.Black)
.weight(weight)
.padding(8.dp)
)
}
Then you can use it to build your table:
#Composable
fun TableScreen() {
// Just a fake data... a Pair of Int and String
val tableData = (1..100).mapIndexed { index, item ->
index to "Item $index"
}
// Each cell of a column must have the same weight.
val column1Weight = .3f // 30%
val column2Weight = .7f // 70%
// The LazyColumn will be our table. Notice the use of the weights below
LazyColumn(Modifier.fillMaxSize().padding(16.dp)) {
// Here is the header
item {
Row(Modifier.background(Color.Gray)) {
TableCell(text = "Column 1", weight = column1Weight)
TableCell(text = "Column 2", weight = column2Weight)
}
}
// Here are all the lines of your table.
items(tableData) {
val (id, text) = it
Row(Modifier.fillMaxWidth()) {
TableCell(text = id.toString(), weight = column1Weight)
TableCell(text = text, weight = column2Weight)
}
}
}
}
Here is the result:
An implementation that supports both fixed and variable column widths, and is horizontally and vertically scrollable would look like the following:
#Composable
fun Table(
modifier: Modifier = Modifier,
rowModifier: Modifier = Modifier,
verticalLazyListState: LazyListState = rememberLazyListState(),
horizontalScrollState: ScrollState = rememberScrollState(),
columnCount: Int,
rowCount: Int,
beforeRow: (#Composable (rowIndex: Int) -> Unit)? = null,
afterRow: (#Composable (rowIndex: Int) -> Unit)? = null,
cellContent: #Composable (columnIndex: Int, rowIndex: Int) -> Unit
) {
val columnWidths = remember { mutableStateMapOf<Int, Int>() }
Box(modifier = modifier.then(Modifier.horizontalScroll(horizontalScrollState))) {
LazyColumn(state = verticalLazyListState) {
items(rowCount) { rowIndex ->
Column {
beforeRow?.invoke(rowIndex)
Row(modifier = rowModifier) {
(0 until columnCount).forEach { columnIndex ->
Box(modifier = Modifier.layout { measurable, constraints ->
val placeable = measurable.measure(constraints)
val existingWidth = columnWidths[columnIndex] ?: 0
val maxWidth = maxOf(existingWidth, placeable.width)
if (maxWidth > existingWidth) {
columnWidths[columnIndex] = maxWidth
}
layout(width = maxWidth, height = placeable.height) {
placeable.placeRelative(0, 0)
}
}) {
cellContent(columnIndex, rowIndex)
}
}
}
afterRow?.invoke(rowIndex)
}
}
}
}
}
The benefit of this implementation is that offers greater flexibility and a relatively simple API. However, there are known caveats, including: variable width columns are less performant and column dividers would have to be done on the cell level.
For variable width columns, it is not as performant as it would require multiple "layout passes". Essentially, this implementation lays out each Row in a LazyColumn, measuring each column cell in each row and storing the largest width value in a MutableState. When a larger width value is encountered for a column, it would trigger a recompose, adjusting all of the other cells in that column to be the larger width. This way, every cell in a column has the same width (and every cell in a row has the same height). For fixed width columns, the performance should be equivalent to other implementations as it doesn't require multiple "layout passes".
Usage:
Table(
modifier = Modifier.matchParentSize(),
columnCount = 3,
rowCount = 10,
cellContent = { columnIndex, rowIndex ->
Text("Column: $columnIndex; Row: $rowIndex")
})
Overloaded composable functions that use the above implementation should be fairly trivial to create, such as having a "header row" be the first row in the table.
My solution is not perfect, but at least the horizontal scroll works. The best I have not found and did not come up with. I hope Google releases its own implementation of DataTable. At the moment DataTable is not implemented for Android.
To set the width of the columns, you have to calculate their weights, but this calculation is not accurate.
private fun calcWeights(columns: List<String>, rows: List<List<String>>): List<Float> {
val weights = MutableList(columns.size) { 0 }
val fullList = rows.toMutableList()
fullList.add(columns)
fullList.forEach { list ->
list.forEachIndexed { columnIndex, value ->
weights[columnIndex] = weights[columnIndex].coerceAtLeast(value.length)
}
}
return weights
.map { it.toFloat() }
}
#Composable
fun SimpleTable(columnHeaders: List<String>, rows: List<List<String>>) {
val weights = remember { mutableStateOf(calcWeights(columnHeaders, rows)) }
Column(
modifier = Modifier
.horizontalScroll(rememberScrollState())
) {
/* HEADER */
Row(modifier = Modifier.fillMaxWidth()) {
columnHeaders.forEachIndexed { rowIndex, cell ->
val weight = weights.value[rowIndex]
SimpleCell(text = cell, weight = weight)
}
}
/* ROWS */
LazyColumn(modifier = Modifier) {
itemsIndexed(rows) { rowIndex, row ->
Row(
modifier = Modifier
.fillMaxWidth()
) {
row.forEachIndexed { columnIndex, cell ->
val weight = weights.value[columnIndex]
SimpleCell(text = cell, weight = weight)
}
}
}
}
}
}
#Composable
private fun SimpleCell(
text: String,
weight: Float = 1f
) {
val textStyle = MaterialTheme.typography.body1
val fontWidth = textStyle.fontSize.value / 2.2f // depends of font used(
val width = (fontWidth * weight).coerceAtMost(500f)
val textColor = MaterialTheme.colors.onBackground
Text(
text = text,
maxLines = 1,
softWrap = false,
overflow = TextOverflow.Ellipsis,
color = textColor,
modifier = Modifier
.border(0.dp, textColor.copy(alpha = 0.5f))
.fillMaxWidth()
.width(width.dp + Size.marginS.times(2))
.padding(horizontal = 4.dp, vertical = 2.dp)
)
}

How to achieve a staggered grid layout using Jetpack compose?

As far as I can see we can only use Rows and Columns in Jetpack Compose to show lists. How can I achieve a staggered grid layout like the image below? The normal implementation of it using a Recyclerview and a staggered grid layout manager is pretty easy. But how to do the same in Jetpack Compose ?
One of Google's Compose sample Owl shows how to do a staggered grid layout. This is the code snippet that is used to compose this:
#Composable
fun StaggeredVerticalGrid(
modifier: Modifier = Modifier,
maxColumnWidth: Dp,
children: #Composable () -> Unit
) {
Layout(
children = children,
modifier = modifier
) { measurables, constraints ->
check(constraints.hasBoundedWidth) {
"Unbounded width not supported"
}
val columns = ceil(constraints.maxWidth / maxColumnWidth.toPx()).toInt()
val columnWidth = constraints.maxWidth / columns
val itemConstraints = constraints.copy(maxWidth = columnWidth)
val colHeights = IntArray(columns) { 0 } // track each column's height
val placeables = measurables.map { measurable ->
val column = shortestColumn(colHeights)
val placeable = measurable.measure(itemConstraints)
colHeights[column] += placeable.height
placeable
}
val height = colHeights.maxOrNull()?.coerceIn(constraints.minHeight, constraints.maxHeight)
?: constraints.minHeight
layout(
width = constraints.maxWidth,
height = height
) {
val colY = IntArray(columns) { 0 }
placeables.forEach { placeable ->
val column = shortestColumn(colY)
placeable.place(
x = columnWidth * column,
y = colY[column]
)
colY[column] += placeable.height
}
}
}
}
private fun shortestColumn(colHeights: IntArray): Int {
var minHeight = Int.MAX_VALUE
var column = 0
colHeights.forEachIndexed { index, height ->
if (height < minHeight) {
minHeight = height
column = index
}
}
return column
}
And then you can pass in your item composable in it:
StaggeredVerticalGrid(
maxColumnWidth = 220.dp,
modifier = Modifier.padding(4.dp)
) {
// Use your item composable here
}
Link to snippet in the sample: https://github.com/android/compose-samples/blob/1630f6b35ac9e25fb3cd3a64208d7c9afaaaedc5/Owl/app/src/main/java/com/example/owl/ui/courses/FeaturedCourses.kt#L161
Your layout is a scrollable layout with rows of multiple cards (2 or 4)
The row with 2 items :
#Composable
fun GridRow2Elements(row: RowData) {
Row(
modifier = Modifier
.fillMaxWidth()
.fillMaxHeight(),
horizontalArrangement = Arrangement.SpaceEvenly
) {
GridCard(row.datas[0], small = true, endPadding = 0.dp)
GridCard(row.datas[1], small = true, startPadding = 0.dp)
}
}
The row with 4 items :
#Composable
fun GridRow4Elements(row: RowData) {
Row(
modifier = Modifier
.fillMaxWidth()
.fillMaxHeight(),
horizontalArrangement = Arrangement.SpaceEvenly
) {
Column {
GridCard(row.datas[0], small = true, endPadding = 0.dp)
GridCard(row.datas[1], small = false, endPadding = 0.dp)
}
Column {
GridCard(row.datas[2], small = false, startPadding = 0.dp)
GridCard(row.datas[3], small = true, startPadding = 0.dp)
}
}
}
The final grid layout :
#Composable
fun Grid(rows: List<RowData>) {
ScrollableColumn(modifier = Modifier.fillMaxWidth()) {
rows.mapIndexed { index, rowData ->
if (rowData.datas.size == 2) {
GridRow2Elements(rowData)
} else if (rowData.datas.size == 4) {
GridRow4Elements(rowData)
}
}
}
Then, you can customize with the card layout you want . I set static values for small and large cards (120, 270 for height and 170 for width)
#Composable
fun GridCard(
item: Item,
small: Boolean,
startPadding: Dp = 8.dp,
endPadding: Dp = 8.dp,
) {
Card(
modifier = Modifier.preferredWidth(170.dp)
.preferredHeight(if (small) 120.dp else 270.dp)
.padding(start = startPadding, end = endPadding, top = 8.dp, bottom = 8.dp)
) {
...
}
I transformed the datas in :
data class RowData(val datas: List<Item>)
data class Item(val text: String, val imgRes: Int)
You simply have to call it with
val listOf2Elements = RowData(
listOf(
Item("Zesty Chicken", xx),
Item("Spring Rolls", xx),
)
)
val listOf4Elements = RowData(
listOf(
Item("Apple Pie", xx),
Item("Hot Dogs", xx),
Item("Burger", xx),
Item("Pizza", xx),
)
)
Grid(listOf(listOf2Elements, listOf4Elements))
Sure you need to manage carefully your data transformation because you can have an ArrayIndexOutOfBoundsException with data[index]
It's now available in version 1.3.0-beta02. You can implement it like this:
LazyVerticalStaggeredGrid(
columns = StaggeredGridCells.Fixed(2),
) {
itemsIndexed((0..50).toList()) { i, item ->
Box(
Modifier
.padding(2.dp)
.fillMaxWidth()
.height(20.dp * i)
.background(Color.Cyan),
)
}
}
Or you can use horizontal view LazyHorizontalStaggeredGrid
Starting from 1.3.0-beta02 you can use the LazyVerticalStaggeredGrid.
Something like:
val state = rememberLazyStaggeredGridState()
LazyVerticalStaggeredGrid(
columns = StaggeredGridCells.Fixed(2),
modifier = Modifier.fillMaxSize(),
state = state,
content = {
items(count) {
//item content
}
}
)
This library will help you LazyStaggeredGrid
Usage:
LazyStaggeredGrid(cells = StaggeredCells.Adaptive(minSize = 180.dp)) {
items(60) {
val randomHeight: Double = 100 + Math.random() * (500 - 100)
Image(
painter = painterResource(id = R.drawable.image),
contentDescription = null,
modifier = Modifier.height(randomHeight.dp).padding(10.dp),
contentScale = ContentScale.Crop
)
}
}
Result:
Better to use LazyVerticalStaggeredGrid
Follow this steps
Step 1 Add the below dependency in your build.gradle file
implementation "androidx.compose.foundation:foundation:1.3.0-rc01"
Step 2 import the below classes in your activity file
import androidx.compose.foundation.lazy.staggeredgrid.LazyVerticalStaggeredGrid
import androidx.compose.foundation.lazy.staggeredgrid.StaggeredGridCells
Step 3 Add LazyVerticalStaggeredGrid like this
LazyVerticalStaggeredGrid(
columns = StaggeredGridCells.Fixed(2),
state = state,
modifier = Modifier.fillMaxSize(),
content = {
val list = listOf(1,2,4,3,5,6,8,8,9)
items(list.size) { position ->
Box(
Modifier.padding(5.dp)
) {
// create your own layout here
NotesItem(list[position])
}
}
})
OUTPUT
I wrote custom staggered column
feel free to use it:
#Composable
fun StaggerdGridColumn(
modifier: Modifier = Modifier,
columns: Int = 3,
content: #Composable () -> Unit,
) {
Layout(content = content, modifier = modifier) { measurables, constraints ->
val columnWidths = IntArray(columns) { 0 }
val columnHeights = IntArray(columns) { 0 }
val placables = measurables.mapIndexed { index, measurable ->
val placable = measurable.measure(constraints)
val col = index % columns
columnHeights[col] += placable.height
columnWidths[col] = max(columnWidths[col], placable.width)
placable
}
val height = columnHeights.maxOrNull()
?.coerceIn(constraints.minHeight.rangeTo(constraints.maxHeight))
?: constraints.minHeight
val width =
columnWidths.sumOf { it }.coerceIn(constraints.minWidth.rangeTo(constraints.maxWidth))
val colX = IntArray(columns) { 0 }
for (i in 1 until columns) {
colX[i] = colX[i - 1] + columnWidths[i - 1]
}
layout(width, height) {
val colY = IntArray(columns) { 0 }
placables.forEachIndexed { index, placeable ->
val col = index % columns
placeable.placeRelative(
x = colX[col],
y = colY[col]
)
colY[col] += placeable.height
}
}
}
}
Using side:
Surface(color = MaterialTheme.colors.background) {
val size = remember {
mutableStateOf(IntSize.Zero)
}
Box(
modifier = Modifier
.fillMaxSize()
.verticalScroll(rememberScrollState())
.onGloballyPositioned {
size.value = it.size
},
contentAlignment = Alignment.TopCenter
) {
val columns = 3
StaggerdGridColumn(
columns = columns
) {
topics.forEach {
Chip(
text = it,
modifier = Modifier
.width(with(LocalDensity.current) { (size.value.width / columns).toDp() })
.padding(8.dp),
)
}
}
}
}
#Composable
fun Chip(modifier: Modifier = Modifier, text: String) {
Card(
modifier = modifier,
border = BorderStroke(color = Color.Black, width = 1.dp),
shape = RoundedCornerShape(8.dp),
elevation = 10.dp
) {
Column(
modifier = Modifier.padding(start = 8.dp, top = 4.dp, end = 8.dp, bottom = 4.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
Box(
modifier = Modifier
.size(16.dp, 16.dp)
.background(color = MaterialTheme.colors.secondary)
)
Spacer(Modifier.height(4.dp))
Text(
text = text,
style = TextStyle(color = Color.DarkGray, textAlign = TextAlign.Center)
)
}
}
}
Really saved a lot of time thanks guys(author of answers). I tried all 3 ways.
This is not an answer rather an observation. For me order of items were not maintained for answer#11. For sample list it did , but with actual list in office work it did not. ordering was altered by one position. I tried even with array list, input list were ordered but views were displaced still.
However, answer#22 did maintained order. And works correctly. I am using this one.
answer#33 did worked as expected as both columns have their individual and independent scroll behaviour
Note: Pagination is still not supported in any of the custom implementation. Manual observation on last item is required to trigger fetching new data. (we can't use pager from pager library, there's no way to make call on pager obj. However, there is manual paging in 'start' code of advance paging codelab (manual paging works there in sample)) https://developer.android.com/codelabs/android-paging#0
Cheers folks.!!
UPDATE with working answer
Please go thorough Android jetpack compose pagination : Pagination not working with staggered layout jetpack compose , Where I have working sample of staggered layout in compose and also with supporting pagination.
Solution : https://github.com/rishikumr/stackoverflow_code_sharing/tree/main/staggered-layout-compose-with_manual_pagination
Working video : https://drive.google.com/file/d/1IsKy0wzbyqI3dme3x7rzrZ6uHZZE9jrL/view?usp=sharing

Categories

Resources