Я — Денис, Middle Android-разработчик в «Black Bricks». Недавно в нашем KMP проекте возникла необходимость добавить рекламный баннер с GIF. В этой статье я расскажу, с какими трудностями мы столкнулись и как удалось реализовать этот функционал.
Исходно, стандартных решений для корректного воспроизведения GIF в Jetpack Compose мы не нашли. Основная сложность заключалась в том, что решение должно было работать одинаково стабильно как на Windows, так и на macOS. Сперва остановились на этом решении. Но уже на первых тестах стало понятно, что GIF больше 4 мегабайт эта реализация не тянет. Загрузка ЦП была под 80%.
Ещё немного пошерстив интернет, наткнулись на реализацию с загрузкой GIF из сети. Нам в целом было не принципиально откуда грузить. Но из-за специфики расположения баннера, и требований отобразить его как можно быстрее, хотелось всё же захардкодить его в сам проект.
Мы немного модифицировали решение для проигрывания из локальных ресурсов. Но так как в реализации используется библиотека javax.imageio.ImageIO
, то нормально она под Windows не завелась. Долго разбираться не стали, тем более этот вариант немного лагал.
По итогу пришли к такому:
@Composable fun GifImage() { val codec = remember { val path = "desktopApp/src/main/resources/images/sample.gif" val file = File(path) val bytes = file.readBytes() Codec.makeFromData(Data.makeFromBytes(bytes)) } AnimatedGif( modifier = Modifier .fillMaxHeight() .aspectRatio(ratio = 1.5f, matchHeightConstraintsFirst = true), codec = codec, ) } @Composable fun AnimatedGif(codec: Codec, modifier: Modifier) { val transition = rememberInfiniteTransition() val frameIndex by transition.animateValue( initialValue = 0, targetValue = codec.frameCount - 1, typeConverter = Int.VectorConverter, animationSpec = infiniteRepeatable( animation = keyframes { durationMillis = 0 for ((index, frame) in codec.framesInfo.withIndex()) { index at durationMillis durationMillis += frame.duration } } ) ) val bitmap = remember { Bitmap().apply { allocPixels(codec.imageInfo) } } Canvas(modifier) { codec.readPixels(bitmap, frameIndex) val imageBitmap = bitmap.asComposeImageBitmap() drawImage( image = imageBitmap, dstSize = IntSize(size.width.toInt(), size.height.toInt()) ) } }
Эта реализация неплохо работает с GIF до 12 мегабайт, и без лагов при скролле списков.
Спасибо за чтение!
Денис Попков
Middle Android разработчик в «Black Bricks»
Если вы нашли неточности/ошибки в статье или просто хотите дополнить её своим мнением — то прошу в комментарии! Или можете написать мне в Telegram.
ссылка на оригинал статьи https://habr.com/ru/articles/841634/
Добавить комментарий