0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Jetpack Compose】3本線のローディングアニメーション作ってみた

Posted at

はじめに

Jetpack Composeでアニメーションとか作りたいなーと思い、
まずは簡単そうなものから作ってみることにした。
たまーに業務でアニメーションを実装する機会があり、その度に手こずりまくるので…
※AIは使用不可

やりたいこと

以下のような3本線のローディングアニメーションを作る

Videotogif.gif

実現に向けて

以下のような方法でこのアニメーションを実現させる。

3つの線の高さ(Height)をそれぞれ動的に描画し、
それぞれの線のアニメーション開始タイミングには時差を設けて、

1つ目の線のアニメーション開始

2つ目の線のアニメーション開始(1つ目のオブジェクトの描画から100ミリ秒後)

3つ目の線のアニメーション開始(1つ目のオブジェクトの描画から200ミリ秒後)

といった順番に描画させる。
また、アニメーションの作成には、animate*AsStateと呼ばれるAPIを使用する。

▼参考

実装

下記のようにアニメーションの関数をComposeで用意する。

// アニメーション描画させる線1本分のデータクラス
data class LoadingItemInfo(
    val height: Dp,
    val width: Dp,
    val color: Color
)

// アニメーションの関数(3本線のView)
@Composable
fun LoadingAnimation() {
    // 3本線のリスト(色もそれぞれ異なるものを指定)
    val boxList = listOf(
        LoadingItemInfo(
            startAnimationDp(0),
            10.dp,
            colorResource(R.color.purple_200)
        ),
        LoadingItemInfo(
            startAnimationDp(1),
            10.dp,
            colorResource(R.color.purple_500)
        ),
        LoadingItemInfo(
            startAnimationDp(2),
            10.dp,
            colorResource(R.color.purple_700)
        )
    )

    // Viewの作成
    Row(
        modifier = Modifier.fillMaxSize(),
        horizontalArrangement = Arrangement.Center,
        verticalAlignment = Alignment.CenterVertically
    ) {
        boxList.forEachIndexed { index, info ->
            Box(
                Modifier
                    .height(info.height)
                    .width(info.width)
                    .background(info.color)
            )

            // 3本線の間隔調整(1つ目と2つ目の線の間に10Dpの間隔調整)
            if (index != boxList.size - 1) {
                Spacer(modifier = Modifier.width(10.dp))
            }
        }
    }
}

// 上下するHeightサイズ(Dp)を返却する関数
@Composable
fun startAnimationDp(
    index: Int,
    minHeight: Dp = 40.dp,
    maxHeight: Dp = 80.dp,
    durationMills: Int = 400
): Dp {
    // サイズの状態
    var expanded by remember { mutableStateOf(false) }

    // Dpサイズをアニメーションで動的に変更
    val scaleDpSize by animateDpAsState(
        targetValue = if (expanded) minHeight else maxHeight,
        animationSpec = infiniteRepeatable(
            animation = tween(durationMills),
            repeatMode = RepeatMode.Reverse
        ),
        finishedListener = { expanded = true }
    )

    // 3本線リストのインデックス値に応じてアニメーションタイミングを変更
    LaunchedEffect(true) {
        delay(index * 100L)
        expanded = true
    }
    return scaleDpSize
}

あとはsetContentとかで作成したLoadingAnimation()を呼び出すだけ。

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            Column(
                Modifier.fillMaxSize(),
                verticalArrangement = Arrangement.Center,
                horizontalAlignment = Alignment.CenterHorizontally
            ) {
                LoadingAnimation()
            }
        }
    }

所感

AIが発達してもっと手間暇なく実装できそうな気がするけど、
やり方や考え方を学ぶという意味では今後も作成してみる価値がありそうだなーと思ってみたり。
もしかしたらまた何か作ってみるかもです。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?