0

I am trying to make a new app with Jetpack Compose and in this app will be a LazyRow with different items in a Box. With every item that is fully visible the background of the box should be changed from the color saved in the data model.

This is the code:

fun MainScreen(navHostController: NavHostController) {
    var bgColor: Color = Color.Red
    val state = rememberLazyListState()
    val fullyVisibleIndices: List<Int> by remember {
        derivedStateOf {
            val layoutInfo = state.layoutInfo
            val visibleItemsInfo = layoutInfo.visibleItemsInfo
            if (visibleItemsInfo.isEmpty()) {
                emptyList()
            } else {
                val fullyVisibleItemsInfo = visibleItemsInfo.toMutableList()

                val lastItem = fullyVisibleItemsInfo.last()

                val viewportHeight = layoutInfo.viewportEndOffset + layoutInfo.viewportStartOffset

                if (lastItem.offset + lastItem.size > viewportHeight) {
                    fullyVisibleItemsInfo.removeLast()
                }

                val firstItemIfLeft = fullyVisibleItemsInfo.firstOrNull()
                if (firstItemIfLeft != null && firstItemIfLeft.offset < layoutInfo.viewportStartOffset) {
                    fullyVisibleItemsInfo.removeFirst()
                }

                fullyVisibleItemsInfo.map { it.index }
            }
        }
    }

    addGrunges()

    Box(
        modifier = Modifier
            .fillMaxSize()
            .background(bgColor)
    ) {
        Column(
            modifier = Modifier
                .fillMaxWidth()
                .padding(top = 100.dp),
            horizontalAlignment = Alignment.CenterHorizontally,
        ) {
            Text(
                text = "Devlet seçin", style = MaterialTheme.typography.h3
            )
            LazyRow(
                state = state,
                modifier = Modifier
                    .fillMaxWidth()
                    .padding(top = 100.dp, bottom = 250.dp)
            ) {
                itemsIndexed(grungesList) { index, items ->
                    bgColor = if (fullyVisibleIndices.contains(index)) items.color else Color.Red
                    ListColumn(model = items)
                }
            }
        }
    }
}

Thanks for your help!

Erdem
  • 57
  • 6

1 Answers1

0

Only fully visible items? Naive implementation

const val contentPadding = 10

@Composable
fun Greeting(models: List<Int> = remember { (0..20).toList() }) {
    val state = rememberLazyListState()
    val highlightState = remember { HighlightState() }
    val hightlightIndices by remember {
        derivedStateOf {
            val layoutInfo = state.layoutInfo
            val visibleItemsInfo = layoutInfo.visibleItemsInfo

            val viewportWidth = layoutInfo.viewportEndOffset - layoutInfo.viewportStartOffset

            if (visibleItemsInfo.isNotEmpty()) {
                val indicies = ArrayList<Int>(visibleItemsInfo.size)
                for (ix in visibleItemsInfo.indices) {
                    val item = visibleItemsInfo[ix]
                    when (ix) {
                        0 -> if (item.offset + contentPadding >= 0) indicies.add(item.index)
                        visibleItemsInfo.size - 1 -> {
                            if (item.offset + item.size + contentPadding < viewportWidth) indicies.add(item.index)
                        }

                        else -> indicies.add(item.index)
                    }
                }
                highlightState.update(indicies)
            }
            highlightState.indicies
        }
    }

    LazyRow(
        modifier = Modifier.fillMaxWidth(),
            //.mouseScroll(state), // for desktop only
        state = state,
        contentPadding = PaddingValues(contentPadding.dp, 0.dp),
        horizontalArrangement = Arrangement.spacedBy(30.dp)
    ) {
        itemsIndexed(models) { index, model ->
            MyListItem(model, hightlightIndices.contains(index))
        }
    }
}

@Composable
fun MyListItem(value: Int, highlight: Boolean) {
    Box(
        modifier = Modifier.height(100.dp)
            .aspectRatio(1f)
            .background(if (highlight) Color.Red else Color.Yellow),
        contentAlignment = Alignment.Center
    ) {
        Text(value.toString())
    }
}

fun <T : Comparable<T>> Iterable<T>.compareTo(other: Iterable<T>): Int {
    val otherI = other.iterator()
    for (e in this) {
        if (!otherI.hasNext()) return 1 // other has run out of elements, so `this` is larger
        val c = e.compareTo(otherI.next())
        if (c != 0) return c // found a position with a difference
    }
    if (otherI.hasNext()) return -1 // `this` has run out of elements, but other has some more, so other is larger
    return 0 // they're the same
}

class HighlightState {

    var indicies: List<Int> = emptyList()
        private set

    fun update(newIndicies: List<Int>) {
        if (indicies.compareTo(newIndicies) != 0)
            indicies = newIndicies
    }
}

result

enter image description here

vitidev
  • 860
  • 1
  • 8
  • 19