减少非焦点项目的不透明度

Reduce opacity of non focused items

我有一个显示在主屏幕上的项目列表,该列表可以垂直滚动。目前我有 5 个项目,但是当用户接近最后一个项目时会添加项目,从而创建无限滚动。

我想让所有项目都淡出,但焦点应该是完全透明的,如下所示:

正如您所看到的那样,左侧和右侧的项目已经褪色并且变小了一点,而焦点项目是完全透明的并且稍微变大了,表明这是焦点项目。

这是我的 Composable 列表:

@Composable
fun HomeScreenList() {
    val homeScreenItems = getItems()
    val listState = rememberLazyListState(Int.MAX_VALUE / 2)
    LazyRow(
        state = listState,
        modifier = Modifier
            .fillMaxWidth(),
        contentPadding = PaddingValues(horizontal = 16.dp, vertical = 8.dp)
    ) {
        items(Int.MAX_VALUE, itemContent = {
            val index = it % homeScreenItems.size
            HomeScreenItem(model = homeScreenItems[index])
        })
    }
}

HomeScreenItem:

@Composable
fun HomeScreenItem(model: HomeScreenViewModel) {
    Card(
        modifier = Modifier
            .padding(horizontal = 10.dp, vertical = 20.dp),
        elevation = 2.dp,
        backgroundColor = model.mBackgroundColor,
        shape = Shapes.large,
    ) {
        Row {
             Image(
        painter = painterResource(id = model.mIcon),
        contentDescription = null,
        contentScale = ContentScale.Crop,
        modifier = Modifier
            .padding(20.dp)
            .size(100.dp)
    )
        }
    }
}

有谁知道我应该怎么做?

HomeScreenItem 添加 isFocused 参数以处理其状态。

现在根据某些条件处理此参数,当该特定项目获得焦点时。

获得焦点的条件:

val scrollState = rememberLazyListState()
val focusableIndex = scrollState.firstVisibleItemIndex + scrollState.layoutInfo.visibleItemsInfo.size/2

或者有一些自定义逻辑来做到这一点。

您可以使用列表状态来确定每个项目离中心有多远,并相应地应用不透明度:

val homeScreenItems = remember {
    listOf(
        Icons.Default.Person,
        Icons.Default.Usb,
        Icons.Default.Keyboard,
    )
}
val listState = rememberLazyListState(Int.MAX_VALUE / 2)
val (rowHalfSize, setRowHalfSize) = remember { mutableStateOf<Int?>(null) }
val horizontalContentPadding = 16.dp
val density = LocalDensity.current
LazyRow(
    state = listState,
    contentPadding = PaddingValues(horizontal = horizontalContentPadding, vertical = 8.dp),
    modifier = Modifier
        .fillMaxWidth()
        .onSizeChanged {
            setRowHalfSize(it.width / 2 - with(density) { horizontalContentPadding.roundToPx() })
        }
) {
    items(Int.MAX_VALUE) { globalIndex ->
        val index = globalIndex % homeScreenItems.size
        val opacity by remember(rowHalfSize) {
            derivedStateOf {
                if (rowHalfSize == null) return@derivedStateOf 0.5f
                val currentItemInfo = listState.layoutInfo.visibleItemsInfo
                    .firstOrNull() { it.index == globalIndex }
                    ?: return@derivedStateOf 0.5f
                val itemHalfSize = currentItemInfo.size / 2
                (1f - minOf(1f, abs(currentItemInfo.offset + itemHalfSize - rowHalfSize).toFloat() / itemHalfSize) * 0.5f)
            }
        }
        Icon(
            homeScreenItems[index], null,
            modifier = Modifier
                .alpha(opacity)
                .scale(opacity)
        )
    }
}

结果: