减少非焦点项目的不透明度
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)
)
}
}
结果:
我有一个显示在主屏幕上的项目列表,该列表可以垂直滚动。目前我有 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)
)
}
}
结果: