Skip to content

Instantly share code, notes, and snippets.

@Mikkareem
Created October 25, 2024 13:37
Show Gist options
  • Save Mikkareem/1f7f98a486edb7ddb195afc2f65ab45d to your computer and use it in GitHub Desktop.
Save Mikkareem/1f7f98a486edb7ddb195afc2f65ab45d to your computer and use it in GitHub Desktop.
import android.os.Build
import androidx.compose.animation.core.Animatable
import androidx.compose.animation.core.LinearEasing
import androidx.compose.animation.core.RepeatMode
import androidx.compose.animation.core.animateFloat
import androidx.compose.animation.core.infiniteRepeatable
import androidx.compose.animation.core.rememberInfiniteTransition
import androidx.compose.animation.core.tween
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.runtime.toMutableStateList
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.drawBehind
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.lerp
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Path
import androidx.compose.ui.graphics.StrokeCap
import androidx.compose.ui.graphics.StrokeJoin
import androidx.compose.ui.graphics.asAndroidPath
import androidx.compose.ui.graphics.drawscope.Stroke
import androidx.compose.ui.graphics.drawscope.rotate
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.core.graphics.flatten
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlin.math.cos
import kotlin.math.sin
@Composable
fun MetaAiLogoAnimation(modifier: Modifier = Modifier) {
val infiniteTransition = rememberInfiniteTransition(
label = "rememberInfiniteTransition"
)
val rotation by infiniteTransition.animateFloat(
initialValue = 0f, targetValue = 360f, label = "rotation",
animationSpec = infiniteRepeatable(
animation = tween(durationMillis = 3000, easing = LinearEasing),
repeatMode = RepeatMode.Restart
)
)
val animations = remember {
List(0) { Animatable(0f) }.toMutableStateList()
}
LaunchedEffect(animations.size) {
while (true) {
animations.indices.forEach { index->
if (index < animations.size / 2f) {
launch {
animations[index].animateTo(
targetValue = 1f,
animationSpec = tween(1000, index * 30)
)
}
launch {
animations[animations.size-1-index].animateTo(
targetValue = 1f,
animationSpec = tween(1000, index * 30)
)
}
}
}
delay(1400)
animations.indices.forEach { index ->
if (index < animations.size / 2f) {
animations[index].snapTo(0f)
animations[animations.size-1-index].snapTo(0f)
launch {
animations[index].animateTo(
targetValue = 1f,
animationSpec = tween(1000, index * 30)
)
}
launch {
animations[animations.size-1-index].animateTo(
targetValue = 1f,
animationSpec = tween(1000, index * 30)
)
}
}
}
delay(4000)
animations.indices.forEach { index ->
animations[index].snapTo(0f)
}
}
}
Spacer(
modifier.fillMaxWidth(.75f).aspectRatio(1f).padding(24.dp)
.drawBehind {
val path = Path().asAndroidPath().apply {
addCircle(
center.x,
center.y,
size.width * .5f,
android.graphics.Path.Direction.CW
)
}
val lines =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) path.flatten() else emptyList()
if (animations.size <= 0) {
animations.addAll(lines.map { Animatable(0f) })
}
val points = lines.mapIndexed { index, it ->
val p1 = Offset(
x = it.start.x,
y = it.start.y
)
val p2 = Offset(
x = p1.x,
y = (2 * center.y - p1.y)
)
lerp(p1, p2, animations[index].value)
}
val newPath = Path().apply {
points.forEachIndexed { index, it ->
if (index == 0) moveTo(it.x, it.y)
else lineTo(it.x, it.y)
}
close()
}
val radians = Math.toRadians(rotation.toDouble())
val cosAngle = cos(radians).toFloat()
val sinAngle = sin(radians).toFloat()
val startPoint = Offset(0.5f - cosAngle / 2, 0.5f - sinAngle / 2)
val endPoint = Offset(0.5f + cosAngle / 2, 0.5f + sinAngle / 2)
val p1 = Offset(
x = size.width * startPoint.x,
y = size.height * startPoint.y
)
val p2 = Offset(
x = size.width * endPoint.x,
y = size.height * endPoint.y
)
val gradient = Brush.linearGradient(
colorStops = arrayOf(
0.01f to Color(0xfffa11f7),
0.18f to Color(0xff871eea),
0.52f to Color(0xff182bdd),
0.85f to Color(0xff0f7cee),
0.99f to Color(0xff0bceff),
),
start = p1,
end = p2
)
rotate(-90f) {
drawPath(
path = newPath,
brush = gradient,
style = Stroke(60.dp.toPx(), cap = StrokeCap.Round, join = StrokeJoin.Round)
)
}
}
)
}
@Preview(showBackground = true)
@Composable
private fun MetaAiLogoAnimationPreview() {
Box(
Modifier
.fillMaxSize()
.background(Color.Black),
contentAlignment = Alignment.Center
) {
MetaAiLogoAnimation()
}
}
@Mikkareem
Copy link
Author

MetaAiLogoAnimation.mov

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