glide icon indicating copy to clipboard operation
glide copied to clipboard

[Glide Compose] How to play/pause a GIF ?

Open j-hiertz opened this issue 1 year ago • 0 comments
trafficstars

Glide Version: 5.0.0-rc1 Glide Compose Version: 1.0.0-beta01

Device/Android Version: Not relevant

Issue details / Repro steps / Use case background:

I am using the GlideImage composable to display gifs in a LazyColumn. I'm looking for a way to pause/play (ideally from the beginning) the GIF.

Using an AndroidView with an ImageView, I can call resource.stop() and resource.startFromFirstFrame() and its works.

With compose I can't see how to reproduce this use case.

What I've tried for the moment, which simulates this behaviour

if (!gifState.isPlaying) {
    GlideImage(
        model = model, contentDescription = null, modifier = Modifier
            .height(150.dp)
            .widthIn(min = 200.dp),
    ) {
        it.dontAnimate()
    }
} else {
    GlideImage(
        model = model, contentDescription = null, modifier = Modifier
            .height(150.dp)
            .widthIn(min = 200.dp),
    )
}

There are 2 problems with this approach:

  • When I click on my cell to change the isPlaying boolean, there is a flicker on the first load between the animated gif and the static image.

  • I'd like to play the GIF from the beginning but it resumes where it left off

Subsidiary question: is it possible not to share the same GifFrameLoader when displaying the same GIF in several different cells?

Because of this, the cells all display the same gif frame, even if the gif is played at different times.

What I also tried was to use AndroidView:

AndroidView(
  factory = { context ->
      val view = ImageView(context).apply {
          layoutParams = ViewGroup.LayoutParams(WRAP_CONTENT, MATCH_PARENT)
          adjustViewBounds = true
      }

      Glide.with(view).asGif().load(model).addListener(object : RequestListener<GifDrawable> {
          override fun onLoadFailed(e: GlideException?, model: Any?, target: Target<GifDrawable>, isFirstResource: Boolean): Boolean {
              return false
          }

          override fun onResourceReady(resource: GifDrawable, model: Any, target: Target<GifDrawable>?, dataSource: DataSource, isFirstResource: Boolean): Boolean {
              if (gifState.isPlaying) {
                  resource.stop()
                  resource.startFromFirstFrame()
              } else {
                  resource.stop()
              }

              view.setImageDrawable(resource)
              return true
          }
      }).into(view)

      view
  },
  update = { view ->
      (view.drawable as? GifDrawable)?.let { gifDrawable ->
          if (gifState.isPlaying) {
              gifDrawable.stop()
              gifDrawable.startFromFirstFrame()
          } else {
              gifDrawable.stop()
          }
      }
  })

This code works correctly for stopping/resuming a GIF from the beginning, but when it is used in several cells, the display becomes very strange and the application ends up crashing with the "Can't restart a running animation" message from the GifFrameLoader.

j-hiertz avatar Jan 08 '24 14:01 j-hiertz