Skip to content

Instantly share code, notes, and snippets.

@suyash
Last active July 3, 2024 20:38
Show Gist options
  • Save suyash/dbc26a22c16426dceceecd81fd38ac52 to your computer and use it in GitHub Desktop.
Save suyash/dbc26a22c16426dceceecd81fd38ac52 to your computer and use it in GitHub Desktop.
Animated Sweep Gradient in Compose
private fun sweepGradientShaderWithOffset(
vararg colorStops: Pair<Float, Color>,
offset: Float = 0f,
center: Offset = Offset.Unspecified
): Brush {
return object : ShaderBrush() {
override fun createShader(size: Size): Shader {
// https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/Brush.kt;l=576-583;drc=a18f72ab3de68971fb30d894d41f4441aa09fd4f
val normalizedCenter =
if (center.isUnspecified) {
size.center
} else {
Offset(center.x.coerceIn(0f, size.width), center.y.coerceIn(0f, size.height))
}
return SweepGradientShader(
center = normalizedCenter,
// https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/Brush.kt;l=370;drc=a18f72ab3de68971fb30d894d41f4441aa09fd4f
colors = colorStops.map { it.second },
colorStops = colorStops.map { it.first },
)
.also { shader ->
shader.setLocalMatrix(
Matrix().also {
it.setRotate(offset * 360, normalizedCenter.x, normalizedCenter.y)
})
}
}
}
}
@Preview(showBackground = true)
@Composable
fun GreetingPreview() {
var textFieldValue by remember { mutableStateOf("") }
val transition = rememberInfiniteTransition(label = "Infinite Transition")
val offset by
transition.animateFloat(
initialValue = 0f,
targetValue = 1f,
animationSpec = infiniteRepeatable(animation = tween(1000, easing = LinearEasing)),
label = "offset animation",
)
Surface(
modifier = Modifier.fillMaxSize().wrapContentSize(),
color = MaterialTheme.colorScheme.background) {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier.fillMaxWidth()) {
Button(
onClick = { /*TODO*/},
border =
BorderStroke(
4.dp,
brush =
sweepGradientShaderWithOffset(
0f to Color.Transparent,
0.25f to MaterialTheme.colorScheme.onPrimary,
0.5f to Color.Transparent,
offset = offset),
),
modifier = Modifier.padding(vertical = 20.dp),
) {
Text(text = "Lorem Ipsum")
}
OutlinedTextField(
value = textFieldValue,
onValueChange = { textFieldValue = it },
colors = OutlinedTextFieldDefaults.colors(),
modifier =
Modifier.padding(vertical = 20.dp)
.border(
width = 4.dp,
brush =
sweepGradientShaderWithOffset(
0f to Color.Transparent,
0.2f to MaterialTheme.colorScheme.primary,
0.4f to Color.Transparent,
offset = offset),
shape = RectangleShape,
),
)
Box(
modifier =
Modifier.padding(vertical = 20.dp)
.size(100.dp)
.background(Color.Transparent)
.border(
width = 10.dp,
brush =
sweepGradientShaderWithOffset(
0f to Color.Transparent,
0.2f to MaterialTheme.colorScheme.primary,
0.4f to Color.Transparent,
offset = offset),
shape = RectangleShape,
),
)
Box(
modifier =
Modifier.padding(vertical = 20.dp)
.size(100.dp)
.background(Color.Transparent)
.border(
width = 10.dp,
brush =
sweepGradientShaderWithOffset(
0f to Color.Transparent,
0.2f to MaterialTheme.colorScheme.primary,
0.4f to Color.Transparent,
offset = offset),
shape = CircleShape,
),
)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment