For some reason there are 2 recompostions happens which results to unable to set a condition for the item to check if it has been already presented to a user.
I would like to make such an animation for LazyGrid (I tried to optimize my code a little bit, but the meaning the same) – https://yasinkacmaz.medium.com/simple-item-animation-with-jetpack-composes-lazygrid-78316992af22
Make an items to appear like bubble effect
There is my code:
private val dataSet: List<String> = listOf("Item 1", "Item 2", "Item 3", "Item 4", "Item 5")
private val data: List<String> = List(5) { dataSet }.flatten()
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContent {
Test_delete_itTheme {
Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
Gallery(
paddingValues = innerPadding,
uiConfig = { data }
)
}
}
}
}
}
@Composable
private fun Gallery(
paddingValues: PaddingValues,
uiConfig: () -> List<String>
) {
val config: List<String> = uiConfig()
val columns = 2
Column(
modifier = Modifier
.fillMaxSize()
.padding(paddingValues)
) {
LazyVerticalGrid(
columns = GridCells.Fixed(columns),
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.spacedBy(8.dp),
horizontalArrangement = Arrangement.spacedBy(8.dp),
content = {
items(config.size) { idx ->
val item: String = config[idx]
val (scale, alpha) = scaleAndAlpha(idx, columns)
MyItem(
modifier = Modifier.graphicsLayer(alpha = alpha, scaleX = scale, scaleY = scale),
text = item
)
}
}
)
}
}
@Composable
private fun MyItem(
modifier: Modifier = Modifier,
text: String
) {
Card(
modifier = modifier.height(150.dp),
shape = RoundedCornerShape(16.dp),
elevation = CardDefaults.cardElevation(8.dp),
colors = CardDefaults.cardColors(
containerColor = Color.Blue,
)
) {
Box(
modifier = Modifier
.weight(1f)
.height(150.dp)
.clip(RoundedCornerShape(16.dp))
) {
Text(
text = text,
color = Color.White
)
}
}
}
@Immutable
private enum class State { PLACING, PLACED }
@Immutable
data class ScaleAndAlphaArgs(
val fromScale: Float,
val toScale: Float,
val fromAlpha: Float,
val toAlpha: Float
)
@OptIn(ExperimentalTransitionApi::class)
@Composable
fun scaleAndAlpha(
args: ScaleAndAlphaArgs,
animation: FiniteAnimationSpec<Float>
): Pair<Float, Float> {
val transitionState = remember { MutableTransitionState(State.PLACING).apply { targetState = State.PLACED } }
val transition = rememberTransition(transitionState, label = "")
val alpha by transition.animateFloat(transitionSpec = { animation }, label = "") {
if (it == State.PLACING) args.fromAlpha else args.toAlpha
}
val scale by transition.animateFloat(transitionSpec = { animation }, label = "") {
if (it == State.PLACING) args.fromScale else args.toScale
}
return alpha to scale
}
val scaleAndAlpha: @Composable (idx: Int, columns: Int) -> Pair<Float, Float> = { idx, columns ->
scaleAndAlpha(
args = ScaleAndAlphaArgs(2f, 1f, 0f, 1f),
animation = tween(300, delayMillis = (idx / columns) * 100)
)
}
I tried to add a condition for the first time presented:
@Composable
private fun Gallery(
paddingValues: PaddingValues,
uiConfig: () -> List<String>
) {
val config: List<String> = uiConfig()
val columns = 2
// Remember a set of already animated indices
val animatedIndices = remember { mutableSetOf<Int>() }
Column(
modifier = Modifier
.fillMaxSize()
.padding(paddingValues)
) {
LazyVerticalGrid(
columns = GridCells.Fixed(columns),
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.spacedBy(8.dp),
horizontalArrangement = Arrangement.spacedBy(8.dp),
content = {
items(config.size) { idx ->
val item: String = config[idx]
// Determine if the item should animate
val shouldAnimate = !animatedIndices.contains(idx)
// If it should animate, mark it as animated
if (shouldAnimate) {
animatedIndices.add(idx)
}
val (scale, alpha) = if (shouldAnimate) {
scaleAndAlpha(idx, columns)
} else {
1f to 1f // No animation
}
MyItem(
modifier = Modifier.graphicsLayer(alpha = alpha, scaleX = scale, scaleY = scale),
text = item
)
}
}
)
}
}
But the issue is that recomposition happens twice here – items(config.size) { idx ->
that makes the condition useless.
What am I missing here?
You need to sign in to view this answers
Leave feedback about this