Skip to content

Instantly share code, notes, and snippets.

@riggaroo
Created December 17, 2024 11:34
Show Gist options
  • Save riggaroo/98df20c4805abb26bdfeec3968865c2f to your computer and use it in GitHub Desktop.
Save riggaroo/98df20c4805abb26bdfeec3968865c2f to your computer and use it in GitHub Desktop.
KeyframesWithSpline Example
import androidx.compose.animation.core.RepeatMode
import androidx.compose.animation.core.VectorConverter
import androidx.compose.animation.core.animateValue
import androidx.compose.animation.core.infiniteRepeatable
import androidx.compose.animation.core.keyframesWithSpline
import androidx.compose.animation.core.rememberInfiniteTransition
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxWithConstraints
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.size
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.drawBehind
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.PathEffect
import androidx.compose.ui.graphics.PointMode
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.layout.boundsInParent
import androidx.compose.ui.layout.onPlaced
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.round
@Preview
@Composable
fun SlaySantaSlay() {
val points = remember { mutableStateListOf<Offset>() }
val infiniteTransition = rememberInfiniteTransition()
BoxWithConstraints (modifier = Modifier.fillMaxSize()) {
val santaSize = with(LocalDensity.current){
100.dp.toPx()
}
val maxSantaX = with (LocalDensity.current) {
maxWidth.toPx() - santaSize
}
val maxSantaY = with(LocalDensity.current){
maxHeight.toPx() - santaSize
}
val offset = infiniteTransition.animateValue(
initialValue = Offset(santaSize, santaSize),
targetValue = Offset(maxSantaX *1.5f, maxSantaY * 0.3f),
typeConverter = Offset.VectorConverter,
animationSpec = infiniteRepeatable(
animation = keyframesWithSpline {
durationMillis = 6000
Offset(santaSize, santaSize) at 0
Offset(maxSantaX * 0.5f, maxSantaY * 0.2f) atFraction 0.1f
Offset(maxSantaX - santaSize, maxSantaY * 0.3f) atFraction 0.3f
Offset(santaSize, maxSantaY * 0.5f) atFraction 0.4f
Offset(maxSantaX * 0.4f, maxSantaY * 0.6f) atFraction 0.5f
Offset(maxSantaX * 0.1f, maxSantaY * 0.7f) atFraction 0.6f
Offset(maxSantaX * 0.3f, maxSantaY * 0.8f) atFraction 0.7f
},
repeatMode = RepeatMode.Restart))
Image(painter = painterResource(id = R.drawable.background),
contentDescription = "Santa",
modifier = Modifier.fillMaxSize(),
contentScale = ContentScale.Crop)
Box(modifier = Modifier.fillMaxSize()
.drawBehind {
drawPoints(
points = points,
pointMode = PointMode.Lines,
color = Color.LightGray,
strokeWidth = 4f,
pathEffect = PathEffect.dashPathEffect(floatArrayOf(30f, 20f))
)
})
Image(painter = painterResource(id = R.drawable.santa),
contentDescription = "Santa",
modifier = Modifier.size(100.dp)
.offset { offset.value.round() }
.onPlaced { points.add(it.boundsInParent().center) }
)
}
}
@riggaroo
Copy link
Author

riggaroo commented Dec 17, 2024

✨ New JetpackCompose animation feature alert ✨

Introducing keyframesWithSpline, unlike the standard keyframes animation spec, keyframesWithSpline produces a natural smooth curve, perfect for working with predefined X,Y coordinates.

Below shows the difference with Santa and the route his sleigh is taking 🎅🏼

📃 Ref docs: https://developer.android.com/reference/kotlin/androidx/compose/animation/core/KeyframesWithSplineSpec

keyframesWithSplineCompare.mp4

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment