【问题标题】:Adding gif into Jetpack Compose将 gif 添加到 Jetpack Compose
【发布时间】:2020-05-30 10:38:58
【问题描述】:

我有一个 gif,我想将其放入我的应用程序中。我知道如何插入图片资源,但是当我尝试添加 gif 时,它变成了静态图片。

DrawImage(image = +imageResource(R.drawable.gif))

有没有人尝试在 Jetpack Compose 中添加 gif,因为在网上很难找到有关如何使用的文档?

【问题讨论】:

  • Quick question 通常这些是最难回答的:)
  • @a_local_nobody 烦人的似乎很多时候都是这样 :)
  • 我还没有和 compose 一起工作过(还),但我觉得这 可能 是一个很好的问题,因为它甚至不可能,因此我的评论 (和我的赞成票)。这都是无关紧要的对话(有人可能会标记并删除它,因为他们应该这样做)但我希望你能找到答案:) 这些天很少看到有趣的问题,遗憾的是
  • 我自己才刚刚开始使用它。与旧的做事方式相比,试验这一切是如何工作的。如果我找到解决方案,我一定会在此处添加(如果尚未删除)
  • 在现有的 Android SDK View 系统中的任何地方都可以制作 GIF 动画吗?例如,至少在 Android 存在的最初几年,ImageView 不会为 GIF 制作动画。开发人员最终使用WebViewMovie (IIRC),直到a bunch of animated-GIF-capable rendering libraries 可用。您的问题表明您期望动画,但这是一个合理的期望吗?

标签: android kotlin gif android-jetpack android-jetpack-compose


【解决方案1】:

从线圈开始 1.3.0 支持的 gif 已添加到 Jetpack Compose 的线圈版本中。所以你可以使用现有的coil docs来支持gif解码。

TL;DR

// Create an ImageLoader

val imgLoader = ImageLoader.invoke(context).newBuilder()
  .componentRegistry {
    if (SDK_INT >= 28) {
      add(ImageDecoderDecoder(context))
    } else {
      add(GifDecoder())
    }
  }.build()

// Use in Image

Image(
  painter = rememberImagePainter(data = R.drawable.YOURBESTGIF, imageLoader = imgLoader),
  ...
)

【讨论】:

    【解决方案2】:

    我能够使用此代码(取自 https://github.com/luca992/coil-composable/blob/master/coil-composable/src/androidMain/kotlin/com/luca992/compose/image/CoilImage.kt 并修改)在 Compose 0.1.0-dev16 中显示动画 GIF:

    import android.graphics.drawable.Animatable
    import android.graphics.drawable.Drawable
    import android.os.Build.VERSION.SDK_INT
    import androidx.annotation.Px
    import androidx.compose.foundation.Image
    import androidx.compose.runtime.*
    import androidx.compose.ui.Modifier
    import androidx.compose.ui.WithConstraints
    import androidx.compose.ui.geometry.Size.Companion.Zero
    import androidx.compose.ui.graphics.ImageAsset
    import androidx.compose.ui.graphics.asImageAsset
    import androidx.compose.ui.platform.ContextAmbient
    import androidx.compose.ui.unit.Constraints.Companion.Infinity
    import androidx.core.graphics.drawable.toBitmap
    import androidx.ui.tooling.preview.Preview
    import coil.ImageLoader
    import coil.decode.GifDecoder
    import coil.decode.ImageDecoderDecoder
    import coil.request.CachePolicy
    import coil.request.LoadRequest
    import coil.request.LoadRequestBuilder
    import coil.size.Scale
    import coil.target.Target
    import kotlinx.coroutines.*
    
    
    @Composable
    fun CoilImage(
        model: Any,
        modifier : Modifier = Modifier,
        customize: LoadRequestBuilder.() -> Unit = {}
    ) {
        WithConstraints(modifier) {
            var width =
                if (constraints.maxWidth > Zero.width && constraints.maxWidth < Infinity) {
                    constraints.maxWidth
                } else {
                    -1
                }
    
            var height =
                if (constraints.maxHeight > Zero.height && constraints.maxHeight < Infinity) {
                    constraints.maxHeight
                } else {
                    -1
                }
    
            //if height xor width not able to be determined, make image a square of the determined dimension
            if (width == -1) width = height
            if (height == -1) height = width
    
            val image = state<ImageAsset> { ImageAsset(width,height) }
            val context = ContextAmbient.current
            var animationJob : Job? = remember { null }
            onCommit(model) {
    
    
                val target = object : Target {
                    override fun onStart(placeholder: Drawable?) {
                        placeholder?.apply {
                            animationJob?.cancel()
                            if(height != -1 && width != -1) {
                                animationJob = image.update(this, width, height)
                            } else if (height == -1) {
                                val scaledHeight = intrinsicHeight * (width / intrinsicWidth )
                                animationJob = image.update(this, width, scaledHeight)
                            } else if (width == -1) {
                                val scaledWidth = intrinsicWidth * (height / intrinsicHeight)
                                animationJob = image.update(this, scaledWidth, height)
                            }
                        }
                    }
    
                    override fun onSuccess(result: Drawable) {
                        animationJob?.cancel()
                        animationJob = image.update(result)
                    }
    
                    override fun onError(error: Drawable?) {
                        error?.run {
                            animationJob?.cancel()
                            animationJob = image.update(error)
                        }
                    }
                }
    
    
    
                val loader = ImageLoader.Builder(context)
                    .componentRegistry {
                        if (SDK_INT >= 28) {
                            add(ImageDecoderDecoder())
                        } else {
                            add(GifDecoder())
                        }
                    }.build()
    
    
                val request = LoadRequest.Builder(context)
                    .data(model)
                    .size(width, height)
                    .scale(Scale.FILL)
                    .diskCachePolicy(CachePolicy.ENABLED)
                    .apply{customize(this)}
                    .target(target)
    
                val requestDisposable = loader.execute(request.build())
    
                onDispose {
                    image.value = ImageAsset(width,height)
                    requestDisposable.dispose()
                    animationJob?.cancel()
                }
            }
            Image(modifier = modifier, asset = image.value)
        }
    }
    
    internal fun MutableState<ImageAsset>.update(drawable: Drawable, @Px width: Int? = null, @Px height: Int? = null) : Job? {
        if (drawable is Animatable) {
            (drawable as Animatable).start()
    
            return GlobalScope.launch(Dispatchers.Default) {
                while (true) {
                    val asset = drawable.toBitmap(
                        width = width ?: drawable.intrinsicWidth,
                        height =  height ?: drawable.intrinsicHeight)
                        .asImageAsset()
                    withContext(Dispatchers.Main) {
                        value = asset
                    }
                    delay(16)
                    //1000 ms / 60 fps = 16.666 ms/fps
                    //TODO: figure out most efficient way to dispaly a gif
                }
            }
        } else {
            value = drawable.toBitmap(
                width = width ?: drawable.intrinsicWidth,
                height =  height ?: drawable.intrinsicHeight)
                .asImageAsset()
            return null
        }
    }
    

    这取决于线圈:

    implementation 'io.coil-kt:coil:0.11.0'
    implementation 'io.coil-kt:coil-gif:0.11.0'
    

    如下使用:

    setContent {
      CoilImage("https://example.com/image.gif")
    }
    

    【讨论】:

      【解决方案3】:

      您可以使用 accompanist - Utils 库来加载可组合的所有图像

      你可以这样使用它:

      GlideImage(
              data = R.drawable.giphy,
              contentDescription = ""
          )
      

      【讨论】:

      • 嗨,谢谢,但是 Glide 的链接已经失效了...
      • @YotiS 这个答案似乎不再正常工作了。请考虑更新或删除它。
      • @EmadRazavi 测试了它!还在工作...
      【解决方案4】:

      这可以使用线圈轻松完成,如下所示

      @Composable
      fun GifImage(
          modifier: Modifier = Modifier,
          imageID: Int
      ){
          val context = LocalContext.current
          val imageLoader = ImageLoader.Builder(context)
              .componentRegistry {
                  if (SDK_INT >= 28) {
                      add(ImageDecoderDecoder(context))
                  } else {
                      add(GifDecoder())
                  }
              }
              .build()
          Image(
              painter = rememberImagePainter(
                  imageLoader = imageLoader,
                  data = imageID,
                  builder = {
                      size(OriginalSize)
                  }
              ),
              contentDescription = null,
              modifier = modifier
          )
      }
      

      使用以下依赖项

      implementation "io.coil-kt:coil-compose:1.4.0"
      implementation "io.coil-kt:coil-gif:1.4.0"
      

      【讨论】:

        猜你喜欢
        • 2020-08-16
        • 1970-01-01
        • 2023-01-07
        • 1970-01-01
        • 2023-01-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-09-17
        相关资源
        最近更新 更多