Как непрерывно анимировать размер текста на основе ленивой прокрутки столбца/ленивого списка в 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)
            }
        }
    }
}

Другие вопросы по тегам