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?

小ネタ: Coil だけで GIF アニメーションの再生/停止をコントロールする

0
Posted at

Android で Compose の画像を扱うライブラリというと、Coil を使われている方は多いのではないでしょうか。

しかしながら、Coil 単体だと GIF アニメーションが扱えないという話題があり、アドオンの coil-gif を追加することで GIF アニメーションを再生できることができるようになります。

それに加えて、GIF の再生・停止を望んだタイミングで行われるようにコントロールするにはどうすればいいでしょうか? 今回はその方法を解説します。

(※ ここでは Coil バージョン 3.4.0 を前提とします)

導入

ドキュメント通りに進めます:

依存を追加しました:

build.gradle.kts
implementation("io.coil-kt.coil3:coil-gif:3.4.0")

ImageLoaderAnimatedImageDecoder または GifDecoder を追加しておきます:

MyGifApp.kt
class MyGifApp : Application(), SingletonImageLoader.Factory {
    override fun newImageLoader(context: PlatformContext): ImageLoader {
        return ImageLoader.Builder(context)
            .components {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
                    add(AnimatedImageDecoder.Factory())
                } else {
                    add(GifDecoder.Factory())
                }
            }
            .build()
    }
}

ドキュメントによるとこれだけでよさそうです。

再生

Gemini に適当なアニメーション動画を作成してもらって、それを ffmpeg で GIF アニメーションにしてもらいました:

ball.gif

この GIF アニメーションを使います。

MyGifAnimation.kt
@Composable
fun MyGifAnimation(modifier: Modifier = Modifier) {
    AsyncImage(
        model = "https://my.app.example/path/to/my.gif",
        contentDescription = null,
        modifier = modifier,
    )
}

表示だけならなにも既存の AsyncImage に変更は不要です。

これだけで GIF アニメーションが再生されるようになりました:

Before After
Jun-01-2026 15-20-05.gif Jun-01-2026 15-16-43.gif

Before ではボールはまったく動きませんが、After では動くようになりました。

コントロール

次にプレイバックのコントロールをしたいと思います。

単純に「再生/停止」ボタンを追加して再生状態をコントロールできるようにしたいと思います:

MyGifAnimationControl.kt
@Composable
fun MyGifAnimationControl(
    onPlayOrPauseClick: () -> Unit,
    modifier: Modifier = Modifier,
) {
    Column(modifier = modifier) {
        MyGifAnimation(
            modifier = Modifier.fillMaxWidth()
        )
        Button(
            onClick = onPlayOrPauseClick,
        ) {
            Text("Play / Pause")
        }
    }
}

image.png

このボタンを押した時のプレイバックのコントロールを実装してみましょう。

まず、MyGifAnimation で再生をコントロールできるように拡張します。

MyGifAnimation.kt
@Composable
fun MyGifAnimation(
    modifier: Modifier = Modifier,
    isPlaying: Boolean = true,
) {
    var animatable by remember { mutableStateOf<Animatable?>(null) }
    LaunchedEffect(isPlaying) {
        animatable?.let {
            if (isPlaying) it.start() else it.stop()
        }
    }
    AsyncImage(
        model = "https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F359439%2Fced0910d-8f64-426c-81cc-ea28209c8948.gif?ixlib=rb-4.1.1&auto=format&gif-q=60&q=75&s=4dd7ae007c0c1d0028f9c42c790129d0",
        contentDescription = null,
        modifier = modifier,
        onSuccess = { state ->
            ((state.result.image as? DrawableImage)?.drawable as? Animatable)?.let {
                animatable = it
            }
        }
    )
}

isPlaying を外から与えて、再生状態を制御できるようにします。

ポイントは AsyncImageonSuccess のコールバックを受け取れるので、ここで得られた成功状態の state から Animatable を得るところです。Animatable を受け取れれば、あとはインターフェースに沿って再生を play / stop でコントロール可能です。

こうなると、MyGifAnimationControl を少し変えればコントロールの完成です:

MyGifAnimationControl.kt
@Composable
fun MyGifAnimationControl(
    modifier: Modifier = Modifier,
) {
    var isPlaying by remember { mutableStateOf(true) }

    Column(modifier = modifier) {
        MyGifAnimation(
            modifier = Modifier.fillMaxWidth(),
            isPlaying = isPlaying,
        )
        Button(
            onClick = {
                isPlaying = !isPlaying
            },
        ) {
            Text(if (isPlaying) "Pause" else "Play")
        }
    }
}

最終的にはこうなりました:

Jun-15-2026 13-49-53.gif

Pause ボタンで一時停止し、Play ボタンで再生できるようになりました。

ただし、再生再開時には始めのフレームからとなってしまうので、
フレーム単位でのプレイバックのコントロールを求めるには別の手段が必要となりそうです。
あくまで動画を使うまでもない簡易的な手段と捉えるのがよさそうですね。

以上です!

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?