1

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
                                                    }
Rudra Dave
  • 101
  • 4
  • 11
  • you don't need animation here, check out [this answer](https://stackoverflow.com/a/71305461/3585796) – Phil Dukhov May 10 '22 at 05:38
  • Thanks, @PylypDukhov. This helped me. Still, there is some problem with the current index i guess the items are not scaling as expected. I will figure it out. Thanks again! – Rudra Dave May 10 '22 at 06:05
  • 1
    Already upvoted :) – Rudra Dave May 10 '22 at 06:23
  • @PylypDukhov I want to scale each item with the scroll can you suggest something for that? – Rudra Dave May 10 '22 at 15:44
  • I didn't get it, do you have a video of same behaviour? – Phil Dukhov May 10 '22 at 16:13
  • @PylypDukhov The same gif I have in the question would help. I want every item to scale continuously. Currently, the only center item is scaling. So far I have tried using the derivedstateof multiple times but it does not work. – Rudra Dave May 10 '22 at 16:46

1 Answers1

4

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)
            }
        }
    }
}

Phil Dukhov
  • 67,741
  • 15
  • 184
  • 220
  • Got it for some reason for me it is not working as my layout column layout is custom and starts from half the screen. But I got your point. Thanks for your answer. – Rudra Dave May 10 '22 at 16:57
  • 1
    hard to say, in half screen size using `Row { Spacer(Modifier.weight(1f)); BoxWithConstraints(Modifier.weight(1f)) { // other part of answer } }` works fine to me – Phil Dukhov May 10 '22 at 17:08
  • Found my mistake thanks for the support. – Rudra Dave May 10 '22 at 17:22