1. 글자가 떨어지고 나서 배경이 깜빡이는 애니메이션 만들기

@Composable
fun TextDropScreen(
    modifier: Modifier = Modifier,
    moveNext: () -> Unit = {}
) {
    val parts = remember {
        listOf("기", "억", "하", "니", "?", "\\n", "얼", "마", " ", "전", " ", "대", "량", "의", " ", "유", "성", "우", "가", "\\n", "떨", "어", "지", "던", " ", "날", ".", ".", ".",
        )
    }

    var animationStartFadeOut by remember { mutableStateOf(false) }

    var partIndex by remember { mutableIntStateOf(0) }
    var partText by remember { mutableStateOf("") }
    //Timber.d("partIndex = $partIndex, partText = $partText")

    LaunchedEffect(parts) {
        while (partIndex < parts.size) {
            val part = parts[partIndex]
            prtText = partText.plus(part)

            delay(TutorialTextDuration.toLong())

            partIndex += 1

            if (partIndex == parts.size) {
		            //text drop complete
                animationStartFadeOut = true
            }
        }
    }

    Box(
        modifier = modifier
            .fillMaxSize()
            .noAnimationClick {
                Timber.d("noAnimationClick = partIndex = ${partIndex}, parts.size = ${parts.size}")
                if (partIndex >= parts.size) {
                    moveNext.invoke()
                }
            }
    ) {
        if (animationStartFadeOut) {
            val infiniteTransition = rememberInfiniteTransition(label = "rememberInfiniteTransition")
            val color by infiniteTransition.animateColor(
                initialValue = Transparent,
                targetValue = BlackA50,
                animationSpec = infiniteRepeatable(
                    animation = tween(2000, easing = LinearEasing),
                    repeatMode = RepeatMode.Reverse
                ), label = ""
            )
        }
        Text(
            text = partText,
            fontSize = 20.nonScaledSp,
            fontFamily = nanumsquare,
            fontWeight = FontWeight.Bold,
            style = YafitTextStyle(
                color = White
            ),
            lineHeight = 37.sp,
            modifier = modifier
                .align(Alignment.TopStart)
                .padding(start = 24.dp, top = 37.dp)
        )
    }
}
  1. 이미지 크기가 커지고 나서 화면이 투명해지면서 사라지게 하기

@Composable
fun LetsTutorial2(
    modifier: Modifier = Modifier,
    moveNext: () -> Unit = {}
) {
    Timber.d("LetsTutorial2")
    var animationStartHand by remember { mutableStateOf(false) }

    var animationStartBall by remember { mutableStateOf(false) }

    var animationStartText by remember { mutableStateOf(false) }

    var animationStartFadeOut by remember { mutableStateOf(false) }

    val sizeScale by animateFloatAsState(
        if (animationStartBall) 1.0f else 0.1f,
        label = "LetsTutorial2_sizeScale",
        finishedListener = {
            Timber.e("finishedListener")
            animationStartText = true
        },
        animationSpec = tween(
            durationMillis = TutorialAnimationDuration,
        )
    )

    val alphaScale by animateFloatAsState(
        if (animationStartFadeOut) 0f else 1f,
        label = "LetsTutorial2_alphaScale",
        finishedListener = {
            Timber.e("finishedListener")
            moveNext.invoke()
        },
        animationSpec = tween(
            durationMillis = TutorialAnimationDuration,
        )
    )

    val parts = remember {
        listOf(
            "그", " ", "안", "에", "\\n", "이", "상", "한", " ", "찹", "쌀", "떡", " ", "같", "은", "\\n", "조", "각", "을", " ", "발", "견", "했", "어",
        )
    }

    var partIndex by remember { mutableStateOf(0) }
    var partText by remember { mutableStateOf("") }
    //Timber.d("partIndex2 = $partIndex2, partText2 = $partText2")

    if (animationStartText) {
        LaunchedEffect(parts) {
            while (partIndex < parts.size) {

                val part = parts[partIndex]

                partText = partText.plus(part)
                delay(TutorialTextDuration.toLong())

                partIndex += 1
            }
        }
    }

    Box(
        modifier = modifier
            .fillMaxSize()
            .graphicsLayer(alpha = alphaScale)
            .noAnimationClick {
                if (partIndex == parts.size) {
                    animationStartFadeOut = true
                }
            }
    ) {
        if (!animationStartHand) {
            LaunchedEffect(true) {
                delay(500L)
                animationStartHand = true
            }
        }

        Text(
            text = partText,
            fontSize = 20.nonScaledSp,
            fontFamily = nanumsquare,
            fontWeight = FontWeight.Bold,
            style = YafitTextStyle(
                color = White
            ),
            lineHeight = 37.sp,
            modifier = modifier
                .align(Alignment.TopStart)
                .padding(start = 24.dp, top = 37.dp)
        )

        Timber.d("AnimatedVisibility Back")
        AnimatedVisibility(
            modifier = modifier
                .align(Alignment.BottomCenter)
                .width(301.dp)
                .height(257.dp),
            visible = animationStartHand,
            enter = fadeIn(animationSpec = tween(TutorialAnimationDuration)),
            exit = fadeOut(animationSpec = tween(TutorialAnimationDuration))
        ) {
            Timber.d("AnimatedVisibility Hand")
            Image(
                painter = painterResource(id = R.drawable.img_tutorial_part2_hand),
                contentDescription = "img_tutorial_part2_hand",
            )
        }

        if (animationStartHand) {
            LaunchedEffect(true) {
                delay(TutorialAnimationDuration.toLong())
                animationStartBall = true
            }
        }

        if (animationStartBall) {
            Image(
                painter = painterResource(id = R.drawable.img_tutorial_part2_ball),
                contentDescription = "img_tutorial_part2_ball",
                modifier = modifier
                    .graphicsLayer(
                        scaleX = sizeScale,
                        scaleY = sizeScale
                    )
                    .align(Alignment.Center)
                    .width(407.dp)
                    .height(434.dp),
            )
        }
    }
}