Как непрерывно анимировать размер текста на основе ленивой прокрутки столбца/ленивого списка в Android - Jetpack Compose?
Я хочу сделать плавный переход для масштабирования текста внутри ленивого столбца. В настоящее время я использую графический слой для анимации масштаба текста на основе первого видимого индекса элемента из состояния списка. Но он не обеспечивает плавной и непрерывной анимации. Я хочу сделать это как анимированный плоский список в родном React. Вот пример того, чего я хочу добиться.
Вот мой код для масштабирования текста на основе выбранных элементов.
val animateSizeText by animateFloatAsState(
targetValue = if (item == selectedItem) {
1f
}
else if (item == selectedItem- 1 || item == selectedItem+ 1) {
0.9f
}
else if (item == selectedItem- 2 || item == selectedItem+ 2) {
0.7f
}
else {
0.5f
},
animationSpec = tween(100, easing = LinearOutSlowInEasing)
)
Модификатор для масштабирования текста:
modifier = Modifier
.graphicsLayer {
scaleY = animateSizeText
scaleX = animateSizeText
}
1 ответ
По сравнению с соответствующим вопросом , вам необходимо включить значение непрозрачности не по умолчанию для других элементов, используя
firstOrNull
блокировать и контролировать, как это зависит от положения прокрутки с множителем. Это довольно простая математика, измените эту формулу в соответствии с нужным вам масштабным эффектом.
val items = remember {
('A'..'Z').map { it.toString() }
}
val listState = rememberLazyListState()
val horizontalContentPadding = 16.dp
val boxSize = 50.dp
BoxWithConstraints {
val halfRowWidth = constraints.maxWidth / 2
LazyRow(
state = listState,
horizontalArrangement = Arrangement.spacedBy(16.dp),
contentPadding = PaddingValues(horizontal = horizontalContentPadding, vertical = 8.dp),
modifier = Modifier
.fillMaxWidth()
) {
itemsIndexed(items) { i, item ->
val opacity by remember {
derivedStateOf {
val currentItemInfo = listState.layoutInfo.visibleItemsInfo
.firstOrNull { it.index == i }
?: return@derivedStateOf 0.5f
val itemHalfSize = currentItemInfo.size / 2
(1f - minOf(1f, abs(currentItemInfo.offset + itemHalfSize - halfRowWidth).toFloat() / halfRowWidth) * 0.5f)
}
}
Box(
contentAlignment = Alignment.Center,
modifier = Modifier
.scale(opacity)
.alpha(opacity)
.size(boxSize)
.background(Color.Blue)
) {
Text(item, color = Color.White)
}
}
}
}