Reputation: 181
I want to make a smooth transition for scaling text inside the lazy column. Currently, I am using the graphics layer to animate the text scale based on the first visible item index from the list state. But it does not provide smooth and continuous animation. I want to make it as an Animated Flat list in React native. Here is an example of what I want to achieve.
Here is my code for scaling text based on the selected items.
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 for scaling text:
modifier = Modifier
.graphicsLayer {
scaleY = animateSizeText
scaleX = animateSizeText
}
Upvotes: 1
Views: 3712
Reputation: 87794
Comparing to related question, you need to enable non default opacity value for other items using firstOrNull
block and control how it depends on scroll position with a multiplier. It's pretty simple math, change this formula according to the scale effect you need.
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)
}
}
}
}
Upvotes: 5