如何使 Jetpack Compose Image 无限动画

问题描述 投票:0回答:5

我有一个

animated-vector
可绘制的。 我希望这个动画矢量在显示该图像时循环动画。 找不到好的解决方案。

        val image = animatedVectorResource(R.drawable.no_devices_animated)
        var atEnd by remember { mutableStateOf(false) }
        Image(
            painter = image.painterFor(atEnd),
            "image",
            Modifier.width(150.dp).clickable {
                atEnd = !atEnd
            },
            contentScale = ContentScale.Fit)

当我点击图像时,它正在播放动画,但随后停止了。这是一种无限的进步。

animation android-jetpack-compose
5个回答
6
投票

将我的解决方案留在这里(使用 compose 1.2.0-alpha07)。

在您的

build.gradle

中添加依赖项
dependencies {
    implementation "androidx.compose.animation:animation:$compose_version"
    implementation "androidx.compose.animation:animation-graphics:$compose_version"
}

并执行以下操作:

@ExperimentalAnimationGraphicsApi
@Composable
fun AnimatedVectorDrawableAnim() {
    val image = AnimatedImageVector.animatedVectorResource(R.drawable.avd_anim)
    var atEnd by remember { mutableStateOf(false) }
    // This state is necessary to control start/stop animation
    var isRunning by remember { mutableStateOf(true) }
    // The coroutine scope is necessary to launch the coroutine 
    // in response to the click event
    val scope = rememberCoroutineScope()
    // This function is called when the component is first launched
    // and lately when the button is pressed
    suspend fun runAnimation() {
        while (isRunning) {
            delay(1000) // set here your delay between animations
            atEnd = !atEnd
        }
    }
    // This is necessary just if you want to run the animation when the
    // component is displayed. Otherwise, you can remove it.
    LaunchedEffect(image) {
        runAnimation()
    }
    Image(
        painter = rememberAnimatedVectorPainter(image, atEnd),
        null,
        Modifier
            .size(150.dp)
            .clickable {
                isRunning = !isRunning // start/stop animation
                if (isRunning) // run the animation if isRunning is true.
                    scope.launch {
                        runAnimation()
                    }
            },
        contentScale = ContentScale.Fit,
        colorFilter = ColorFilter.tint(Color.Red)
    )
}

如果您需要从头开始重复动画,我发现的唯一方法是使用动画矢量绘图中声明的信息创建两个矢量绘图,例如

ic_start
ic_end
并执行以下操作:

// this is the vector resource of the start point of the animation
val painter = rememberVectorPainter(
    image = ImageVector.vectorResource(R.drawable.ic_start)
)
val animatedPainter = rememberAnimatedVectorPainter(
    animatedImageVector = AnimatedImageVector.animatedVectorResource(R.drawable.avd_anim),
    atEnd = !atEnd
)

Image(
    painter = if (atEnd) painter else animatedPainter,
    ...
)

因此,当动画矢量到达结束位置时,绘制静态图像。延迟后,再次播放动画。如果需要连续重复,请将延迟设置为与动画相同的持续时间。

结果如下:


2
投票

根据https://developer.android.com/jetpack/compose/resources#animated-vector-drawables

val image = AnimatedImageVector.animatedVectorResource(R.drawable.animated_vector)
val atEnd by remember { mutableStateOf(false) }
Icon(
    painter = rememberAnimatedVectorPainter(image, atEnd),
    contentDescription = null
)

使动画无限循环:

val image = AnimatedImageVector.animatedVectorResource(id = vectorResId)
var atEnd by remember { mutableStateOf(false) }
Image(
    painter = rememberAnimatedVectorPainter(animatedImageVector = image, atEnd = atEnd),
    contentDescription = null,
)
LaunchedEffect(Unit) {
    while (true) {
        delay(animDuration)
        atEnd = !atEnd
    }
}

1
投票

无静态图像无限循环解决方案:

最好使用循环的动画矢量绘图。

首先在 build.gradle 中添加依赖项

dependencies {
    implementation "androidx.compose.animation:animation:$compose_version"
    implementation "androidx.compose.animation:animation-graphics:$compose_version"
}

动画循环加载器

@OptIn(ExperimentalAnimationGraphicsApi::class)
@Composable
fun Loader() {
    val image = AnimatedImageVector.animatedVectorResource(id = R.drawable.loader_cycle)
    var atEnd by remember {
        mutableStateOf(false)
    }
    val painterFirst = rememberAnimatedVectorPainter(animatedImageVector = image, atEnd = atEnd)
    val painterSecond = rememberAnimatedVectorPainter(animatedImageVector = image, atEnd = !atEnd)

    val isRunning by remember { mutableStateOf(true) }
    suspend fun runAnimation() {
        while (isRunning) {
            atEnd = !atEnd
            delay(image.totalDuration.toLong())
        }
    }
    LaunchedEffect(image) {
        runAnimation()
    }
    Image(
        painter = if (atEnd) painterFirst else painterSecond,
        contentDescription = null,
    )
}

现在我没有看到任何重新启动画家以重新开始的选项 - 您需要倒回它。因此,在这个解决方案中,我们创建了两个画家。其中之一以

!atEnd
开头。每次
atEnd
更改时,它们都会完成自己的工作,但 我们从开始到结束只显示一个动画。另一个正在默默地倒带动画。


0
投票

我尝试使用这种方法实现加载旋转器,但遇到了一些问题。

我对建议的解决方案有疑问,动画会倒退到开头。为了防止这种情况,正如 @nglauber 建议的那样,我尝试在动画结束时切换到静态向量。不幸的是,这并不顺利,因为动画必须等待延迟才能重新启动。

这是我使用的解决方法。

@OptIn(ExperimentalAnimationGraphicsApi::class)
@Composable
fun rememberAnimatedVectorPainterCompat(image: AnimatedImageVector, atEnd: Boolean): Painter {
    val animatedPainter = rememberAnimatedVectorPainter(image, atEnd)
    val animatedPainter2 = rememberAnimatedVectorPainter(image, !atEnd)
    return if (atEnd) {
        animatedPainter
    } else {
        animatedPainter2
    }
}

0
投票

受到Artur Kasprzak的回答的启发,以下代码对我有用:

@ExperimentalAnimationGraphicsApi
@Composable
fun rememberAnimatedVectorPainterWithInfiniteRepeatMode(
    animatedImageVector: AnimatedImageVector,
    atEnd: Boolean,
): Painter {
    var atEndState by remember { mutableStateOf(atEnd) }
    val painter = rememberAnimatedVectorPainter(animatedImageVector, atEndState)
    val painterReverse = rememberAnimatedVectorPainter(animatedImageVector, !atEndState)
    LaunchedEffect(Unit) { atEndState = !atEndState }
    return if (atEndState) painter else painterReverse
}

在通话网站上:

val painter = rememberAnimatedVectorPainterWithInfiniteRepeatMode(image,false)
Image(painter = painter,contentDescription = null)
© www.soinside.com 2019 - 2024. All rights reserved.