Hey all Does anyone know how to make the animated ...
# compose
a
Hey all Does anyone know how to make the animated vector animates infinitely?
Copy code
val image = animatedVectorResource(id = R.drawable.animated_vector)
val atEnd by remember { mutableStateOf(false) }
Icon(
    painter = image.painterFor(atEnd = atEnd),
    contentDescription = null // decorative element
)
e
I don't think
AnimatedVectorDrawable
has a good API for that and instead I think you need to add a Animatable2.AnimationCallback and restart it when it ends. Which seems like what you're trying to do, but you need to restart the animation and reset your atEnd state. However, since the animation doesn't require recompositing, I think you can just add a listener that restarts the drawable. I.e I don't think you need a composable state.
a
Thanks Andreas.
d
Seems like it would be useful to expose the underlying
Transition
for AnimatedVector, or accept a
MutableTransitionState
. Until then, we have a feature
RenderVectorGroup
that supports overwriting the values defined in a static vector drawable. Here's an example:
Copy code
val vd = ImageVector.vectorResource(id = R.drawable.vector_icon_five_bars)
                    val map = remember { mutableStateMapOf<String, VectorConfig>() }

                    val painter = rememberVectorPainter(
                        defaultWidth = vd.defaultWidth,
                        defaultHeight = vd.defaultHeight,
                        viewportWidth = vd.viewportWidth,
                        viewportHeight = vd.viewportHeight,
                        name = vd.name,
                        tintColor = vd.tintColor,
                        tintBlendMode = vd.tintBlendMode,
                    ) { _, _ ->
                        val trimPathOffset by rememberInfiniteTransition().animateFloat(
                            initialValue = 0f,
                            targetValue = 1f,
                            animationSpec = infiniteRepeatable(tween(200))
                        )
                        map["class4"] = object: VectorConfig {
                            override fun <T> getOrDefault(
                                property: VectorProperty<T>,
                                defaultValue: T
                            ): T {
                                return if (property == VectorProperty.TrimPathOffset) {
                                    trimPathOffset as T
                                } else {
                                    defaultValue
                                }
                            }
                        }
                        RenderVectorGroup(group = vd.root, map)
                    }
                    Icon(painter, null)
a
Thank you @Doris Liu I managed to implemented it like below, I'm not sure if there's any performance issues:
Copy code
val infiniteTransition = rememberInfiniteTransition()
val trimOffset by infiniteTransition.animateFloat(
    initialValue = 0f,
    targetValue = 1f,
    animationSpec = infiniteRepeatable(
        animation = tween(1500, easing = LinearEasing),
        repeatMode = RepeatMode.Restart
    )
)

Image(
    ImageVector.Builder(
        defaultWidth = 100.dp,
        viewportWidth = 612.74f,
        defaultHeight = 35.8.dp,
        viewportHeight = 218.77f
    ).addPath(
        pathData = remember { addPathNodes("") },
        stroke = SolidColor(Color(0xff231f20)),
        strokeLineCap = StrokeCap.Round,
        strokeLineWidth = 50f,
        trimPathStart = 0.6f,
        trimPathOffset = trimOffset,
    ).build(), null
)
d
This seems expensive as the ImageVector gets rebuilt whenever the trimPathOffset changes, which is every frame. It'd be nice to create one
Path
object from the provided pathData and just mutate the trimPathStart/End/Offset for the animation purpose. @Nader Jawad Do we have plans for adding trimPathStart/End/Offset support directly on
Path
? 🙂
n
ImageVector
is mainly used for deserialization of vector graphics from a vector drawable or elsewhere. It is used as input to`remberVectorPainter` which creates the sub composition on your behalf by calling similar methods. Instead you can create the Vector painter directly by using the sub composition methods for
Path
and `Group`skipping ImageVector entirely. This will reuse the same objects internally should the vector subcomposition change
a
@Doris Liu Okay. I've changed it to the way you posted before. Thank you!
d
The solution that Nader suggested above may be a simpler solution, especially if your vector has a relatively simple group structure. 🙂 Here's an example: https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:compose/[…]%20file:compose&amp;ss=androidx%2Fplatform%2Fframeworks%2Fsupport
👍 1
1