kotlin 在Jetpack编写中检测LazyRow内居中的项目

ma8fv8wu  于 2023-03-03  发布在  Kotlin
关注(0)|答案(1)|浏览(132)

我想做一个水平列表,有一个旋转木马的效果,中间的项目必须位于屏幕的中心,与上一个和下一个项目只显示其边缘。此外,中心项目应稍微放大,以强调其中心位置,见下面的gif。

我也想改变背景色时,项目是在中心,但它不为我工作,我的尝试下面有点工作,有时它的速度慢,有时它只是不工作。
你能增强它,使中心项目自动得到更新和缩放?

    • 我的密码:**
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun MyCards(list: List<String>) {

    val state = rememberLazyListState()
    val snappingLayout = remember(state) { SnapLayoutInfoProvider(state) }
    val flingBehavior = rememberSnapFlingBehavior(snappingLayout)

     LazyRow(
            modifier = Modifier.wrapContentHeight(),
            verticalAlignment = Alignment.CenterVertically,
            state = state,
            flingBehavior = flingBehavior
        ) {
            items(list) {
                MyCard(state,list.indexOf(it))
            }
        }

}

@Composable
private fun MyCard(state: LazyListState, index: Int) {

    val isCentered = remember { mutableStateOf(false) }

    val itemInfo = state.layoutInfo.visibleItemsInfo.firstOrNull { it.index == index}

    itemInfo?.let {
        val center = state.layoutInfo.viewportEndOffset / 2
        val childCenter = it.offset + it.size / 2
        val target = childCenter - center
        if (index == target) isCentered.value = true
    }

    Card(
        modifier = Modifier
            .fillMaxWidth()
            .wrapContentHeight()
            .padding(10.dp, 10.dp, 10.dp, 200.dp),
        elevation = 5.dp,
        shape = RoundedCornerShape(10.dp),
        backgroundColor = if (isCentered.value) Color.Red else Color.Blue

    ) {
        Image(
            modifier = Modifier
                .padding(70.dp)
                .height(400.dp)
                .width(100.dp)
                .alpha(0f),
            painter = painterResource(id = R.drawable.ico_main),
            contentDescription = null
        )
    }

}
sqxo8psd

sqxo8psd1#

在你的Card中,你可以使用类似于:

val backgroundColor by remember {
    derivedStateOf {

        val layoutInfo = state.layoutInfo
        val visibleItemsInfo = layoutInfo.visibleItemsInfo
        val itemInfo = visibleItemsInfo.firstOrNull { it.index == index}

        itemInfo?.let {

            //First item
            if (itemInfo.index == 0 && itemInfo.offset == 0)
                return@derivedStateOf Red

            //Last item
            val viewportWidth = layoutInfo.viewportEndOffset + layoutInfo.viewportStartOffset
            if (itemInfo.index + 1 == layoutInfo.totalItemsCount &&
                itemInfo.offset + itemInfo.size <= viewportWidth)
            return@derivedStateOf Red

            //Other items
            val delta = 5
            val center = state.layoutInfo.viewportEndOffset / 2
            val childCenter = it.offset + it.size / 2
            val target = childCenter - center
            if (target in -delta..delta) return@derivedStateOf Red
        }
        Blue
    }
}

val scale by remember {
    derivedStateOf {            
        val currentItem = state.layoutInfo.visibleItemsInfo.firstOrNull { it.index == index } ?: return@derivedStateOf 1.0f
        val halfRowWidth = state.layoutInfo.viewportSize.width/2
        (1f - minOf(1f, abs(currentItem.offset + (currentItem.size / 2) - halfRowWidth ).toFloat() / halfRowWidth) * 0.10f)
    }
}

然后应用它

Card(
        modifier = Modifier
            .fillMaxWidth()
            .wrapContentHeight()
            .padding(10.dp, 10.dp, 10.dp, 200.dp)
            .scale(scale)
            .zIndex(scale * 10),
        //
        backgroundColor = backgroundColor
    )

相关问题