1

Is there a way where I can observer the Cyan color field position progress in percentage/fraction, to get 100% when it is fully visible and 0% when it is closed(list elements are scrolled), the idea is that I want to remove "First Last" text on left with animation.

Here is the code:

val scaffoldState = rememberScaffoldState()
val lazyListState = rememberLazyListState()

Scaffold(
    scaffoldState = scaffoldState,
    topBar = {
        TopAppBar(
            title = {
                Text(fontSize = 30.sp, text = "Account", color = Color.White)
            },
            backgroundColor = Color.Black
        )
    },
    content = {
        LazyColumn(state = lazyListState) {
            item {
                Row(
                    modifier = Modifier
                        .fillMaxWidth()
                        .wrapContentHeight()
                        .background(color = Color.Cyan)
                ) {
                    Text(
                        text = "First Last",
                        fontSize = 20.sp,
                        color = Color.White,
                        modifier = Modifier
                            .padding(20.dp)
                    )
                }
            }

            items(list) {
                Row(
                    Modifier
                        .fillMaxWidth()
                        .wrapContentHeight()
                        .padding(start = 20.dp, top = 10.dp, bottom = 10.dp)
                ) {
                    Text(it)
                }
            }
        }
    }
)

enter image description here

Svilen Rusev
  • 309
  • 4
  • 15

1 Answers1

4

You can achieve this by getting height of your RowItem and using a derivedStateOf that calculates using this height or getting it using lazyListState.layoutInfo.visibleItemsInfo

val percent = remember {
    derivedStateOf {
        val isFirstItemVisible = lazyListState.firstVisibleItemIndex == 0
        // If your first item is not visible then our progress is 0%
        if (isFirstItemVisible) {

            // ALTERNATIVE 1
//                // This is for not dividing when it's 0 initially
//                if (rowHeight == 0f) {
//                    100f
//                } else {
//                    (100f * (1 - lazyListState.firstVisibleItemScrollOffset / rowHeight)).roundToInt()
//                }

            // ALTERNATIVE 2
            val items = lazyListState.layoutInfo.visibleItemsInfo
            if (items.isNotEmpty()) {
                val firstItem = lazyListState.layoutInfo.visibleItemsInfo.first()
                (100f * (1f + firstItem.offset / firstItem.size.toFloat())).roundToInt()
            } else {
                100f
            }
        } else {
            0f
        }

    }
}

Full example

You don't have to set Modifier.onSizeChanged{} with alternative 2

@Composable
private fun MyList() {

    val lazyListState = rememberLazyListState()
    var rowHeight by remember { mutableStateOf(0f) }
    val list = mutableListOf<String>()

val percent = remember {
    derivedStateOf {
        val isFirstItemVisible = lazyListState.firstVisibleItemIndex == 0
        // If your first item is not visible then our progress is 0%
        if (isFirstItemVisible) {

            // ALTERNATIVE 1
//                // This is for not dividing when it's 0 initially
//                if (rowHeight == 0f) {
//                    100f
//                } else {
//                    (100f * (1 - lazyListState.firstVisibleItemScrollOffset / rowHeight)).roundToInt()
//                }

            // ALTERNATIVE 2
            val items = lazyListState.layoutInfo.visibleItemsInfo
            if (items.isNotEmpty()) {
                val firstItem = lazyListState.layoutInfo.visibleItemsInfo.first()
                (100f * (1f + firstItem.offset / firstItem.size.toFloat())).roundToInt()
            } else {
                100f
            }
        } else {
            0f
        }

    }
}

    repeat(20) {
        list.add("Row $it")
    }


    Box(contentAlignment = Alignment.TopEnd) {

        LazyColumn(state = lazyListState) {
            item {
                Row(
                    modifier = Modifier
                        .fillMaxWidth()
                        .wrapContentHeight()
                        .onSizeChanged {
                            if (rowHeight == 0f) {
                                rowHeight = it.height.toFloat()
                            }
                        }
                        .background(color = Color.Cyan)
                ) {
                    Text(
                        text = "First Last",
                        fontSize = 20.sp,
                        color = Color.White,
                        modifier = Modifier
                            .padding(20.dp)
                    )
                }
            }

            items(items = list) {
                Row(
                    Modifier
                        .fillMaxWidth()
                        .wrapContentHeight()
                        .padding(start = 20.dp, top = 10.dp, bottom = 10.dp)
                ) {
                    Text(it)
                }
            }
        }

        Text(
            "Percent: ${percent.value}"
        )
    }
}

Result

enter image description here

Thracian
  • 43,021
  • 16
  • 133
  • 222