Skip to content

Instantly share code, notes, and snippets.

@ardakazanci
Created January 6, 2024 15:07
Show Gist options
  • Save ardakazanci/acfcd9144474deac7bc5fa3d0531f0a9 to your computer and use it in GitHub Desktop.
Save ardakazanci/acfcd9144474deac7bc5fa3d0531f0a9 to your computer and use it in GitHub Desktop.
Heart Shape and Animation for Jetpack Compose
@Composable
fun AnimatedHeartShape() {
BoxWithConstraints(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
) {
var clicked by remember { mutableStateOf(false) }
val heartSize = 400.dp
val heartSizePx = with(LocalDensity.current) { heartSize.toPx() }
val infiniteTransition = rememberInfiniteTransition(label = "Sample rememberInfiniteTransition")
val animatedStrokePhase = infiniteTransition.animateFloat(
initialValue = 0f,
targetValue = heartSizePx * 2,
animationSpec = infiniteRepeatable(
animation = tween(2000, easing = LinearEasing),
repeatMode = RepeatMode.Restart
), label = "Sample AnimatedFloat"
)
val continuousScale = infiniteTransition.animateFloat(
initialValue = 0.8f,
targetValue = 1f,
animationSpec = infiniteRepeatable(
animation = tween(500, easing = LinearEasing),
repeatMode = RepeatMode.Reverse
), label = "Sample AnimatedFloat"
)
val disappearScale by animateFloatAsState(
targetValue = if (clicked) 0f else 1f,
animationSpec = tween(
durationMillis = 500,
easing = LinearOutSlowInEasing
), label = "Sample Float As State"
)
Canvas(
modifier = Modifier
.size(heartSize)
.clickable { clicked = true }
) {
val path = Path().apply {
moveTo(heartSizePx / 2, heartSizePx / 5)
cubicTo(heartSizePx * 3 / 4, 0f, heartSizePx, heartSizePx / 3, heartSizePx / 2, heartSizePx)
cubicTo(0f, heartSizePx / 3, heartSizePx / 4, 0f, heartSizePx / 2, heartSizePx / 5)
close()
}
val gradient = Brush.linearGradient(
colors = listOf(Color.Red, Color(0xFF841C26), Color(0xFFBA274A)),
start = Offset(0f, 0f),
end = Offset(heartSizePx, heartSizePx)
)
val combinedScale = continuousScale.value * disappearScale
scale(combinedScale, combinedScale, pivot = Offset(heartSizePx / 2, heartSizePx / 2)) {
drawPath(path, gradient)
val lineGradient = Brush.linearGradient(
colors = listOf(Color(0xFFFFE45E), Color(0xFFFF6392)),
start = Offset(0f, 0f),
end = Offset(heartSizePx, heartSizePx)
)
val pathEffect = PathEffect.dashPathEffect(
intervals = floatArrayOf(heartSizePx, heartSizePx),
phase = -animatedStrokePhase.value
)
drawPath(
path = path,
brush = lineGradient,
style = Stroke(width = 8.dp.toPx(), pathEffect = pathEffect)
)
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment