4

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

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

有没有人尝试在 Jetpack Compose 中添加一个 gif,就像在网上很难找到文档一样?

4

4 回答 4

3

1.3.0Jetpack Compose 的 Coil 版本从支持的线圈gif 开始。因此,您可以使用现有的线圈文档来支持 gif 解码。

TL;博士

// 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),
  ...
)
于 2021-09-07T17:18:29.673 回答
2

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

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")
}
于 2020-08-22T17:24:31.400 回答
1

您可以将伴奏- Utils 库用于加载可组合的所有图像

你可以像这样使用它:

GlideImage(
        data = R.drawable.giphy,
        contentDescription = ""
    )
于 2021-03-07T05:27:08.737 回答
0

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

@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"
于 2022-01-20T15:20:47.127 回答