Skip to content

Instantly share code, notes, and snippets.

@icai
Last active May 22, 2024 15:16
Show Gist options
  • Save icai/dde5067dbeabc7ca28189bb5cc01e958 to your computer and use it in GitHub Desktop.
Save icai/dde5067dbeabc7ca28189bb5cc01e958 to your computer and use it in GitHub Desktop.
CuSwitch.kt
@Composable
fun CustomSwitch(
checked: Boolean,
onCheckedChange: (Boolean) -> Unit,
modifier: Modifier = Modifier,
trackColor: Color = VoicenotifyTheme.colorScheme.primary,
thumbColor: Color = Color.White,
innerCircleColor: Color = Color.Gray,
animationDuration: Int = 300
) {
val thumbRadius = 16.dp
val trackWidth = 48.dp
val trackHeight = 32.dp
val trackRadius = trackHeight / 2
val thumbPosition = remember { Animatable(if (checked) 1f else 0f) }
val innerCircleRadius = remember { Animatable(thumbRadius.value * 0.5f) }
LaunchedEffect(checked) {
thumbPosition.animateTo(
if (checked) 1f else 0f,
animationSpec = tween(durationMillis = animationDuration)
)
innerCircleRadius.animateTo(
if (checked) thumbRadius.value * 0.75f else thumbRadius.value * 0.5f,
animationSpec = tween(durationMillis = animationDuration)
)
}
Canvas(
modifier = modifier
.size(trackWidth, trackHeight)
.pointerInput(Unit) {
detectTapGestures {
onCheckedChange(!checked)
}
}
) {
// Draw track
drawRoundRect(
color = trackColor.copy(alpha = 0.5f),
size = size,
cornerRadius = CornerRadius(x = trackRadius.toPx(), y = trackRadius.toPx())
)
// Draw thumb
val thumbOffsetX = thumbPosition.value * (size.width - thumbRadius.toPx() * 2)
val thumbCenter = Offset(x = thumbOffsetX + thumbRadius.toPx(), y = size.height / 2)
drawCircle(
color = thumbColor,
radius = thumbRadius.toPx(),
center = thumbCenter,
style = Fill
)
// Draw inner circle
drawCircle(
color = innerCircleColor,
radius = innerCircleRadius.value.dp.toPx(),
center = thumbCenter,
style = Fill
)
}
}
@Composable
private fun CuSwitch(
modifier: Modifier = Modifier,
checked: MutableState<Boolean> = remember { mutableStateOf(false) },
onCheckedChange: (Boolean) -> Unit = {}
) {
val width = 34.dp
val height = 19.dp
val gapBetweenThumbAndTrackEdge = 2.dp
// 4 15 +
val thumbRadius = (height / 2) - gapBetweenThumbAndTrackEdge
val animatePosition = animateFloatAsState(
targetValue = if (checked.value) {
with(LocalDensity.current) { (width - thumbRadius - gapBetweenThumbAndTrackEdge).toPx() }
} else {
with (LocalDensity.current) { (thumbRadius + gapBetweenThumbAndTrackEdge).toPx() }
}
)
val checkedThumbColor = VoicenotifyTheme.colors.colorOnCustom
val uncheckedThumbColor = VoicenotifyTheme.colors.colorThumbOffCustom
val checkedTrackColor = VoicenotifyTheme.colors.colorPrimary
val uncheckedTrackColor = VoicenotifyTheme.colors.colorOffCustom
Canvas(
modifier = modifier
.size(width = width, height = height)
.pointerInput(Unit) {
detectTapGestures(
onTap = {
checked.value = !checked.value
onCheckedChange(checked.value)
}
)
}
) {
drawRoundRect(
color = if (checked.value) checkedTrackColor else uncheckedTrackColor,
cornerRadius = CornerRadius(x = 10.dp.toPx(), y = 10.dp.toPx())
)
drawCircle(
color = if (checked.value) checkedThumbColor else uncheckedThumbColor,
radius = thumbRadius.toPx(),
center = Offset(
x = animatePosition.value,
y = size.height / 2
)
)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment