Skip to content

Instantly share code, notes, and snippets.

@ardakazanci
Created April 28, 2024 06:15
Show Gist options
  • Save ardakazanci/0256b50c28de6472ed7454c7d0a6b418 to your computer and use it in GitHub Desktop.
Save ardakazanci/0256b50c28de6472ed7454c7d0a6b418 to your computer and use it in GitHub Desktop.
RulerView - Jetpack Compose
@Composable
fun RulerView(
startValue: Int,
endValue: Int,
step: Int
) {
val density = LocalDensity.current
val scrollState = rememberScrollState()
val sectionWidth = 80.dp
var sliderValue by remember { mutableFloatStateOf(0.5f) }
var angleSliderValue by remember { mutableFloatStateOf(0f) }
var colorSliderValue by remember { mutableFloatStateOf(0f) }
var sliderX by remember { mutableFloatStateOf(0f) }
var sliderY by remember { mutableFloatStateOf(0f) }
var sliderZ by remember { mutableFloatStateOf(1f) }
var isAnimating by remember { mutableStateOf(false) }
val currentValue = remember(scrollState.value, with(density) { sectionWidth.toPx() }) {
startValue + (scrollState.value / with(density) { sectionWidth.toPx() }).toInt() * step
}
Column {
SliderControl("Thickness and Length Adjustment:", sliderValue, 0.1f..3f) {
sliderValue = it
}
SliderControl("Angle Adjustment:", angleSliderValue, -45f..45f) { angleSliderValue = it }
SliderControl("Color Change:", colorSliderValue, 0f..1f) { colorSliderValue = it }
SliderControl("Rotation on X Axis:", sliderX, -360f..360f) { sliderX = it }
SliderControl("Rotation on Y Axis:", sliderY, -360f..360f) { sliderY = it }
SliderControl("Scaling on Z Axis:", sliderZ, 0.5f..2f) { sliderZ = it }
Button(onClick = { isAnimating = !isAnimating }) {
Text(if (isAnimating) "Stop Animation" else "Start Animation")
}
Spacer(modifier = Modifier.height(24.dp))
Box(modifier = Modifier.graphicsLayer {
rotationX = sliderX
rotationY = sliderY
scaleX = sliderZ
scaleY = sliderZ
}) {
Image(
modifier = Modifier
.clip(RoundedCornerShape(20.dp))
.fillMaxWidth()
.height(60.dp)
.align(Alignment.TopEnd),
contentScale = ContentScale.Crop,
painter = painterResource(id = android.R.drawable.button_onoff_indicator_off),
contentDescription = ""
)
Box(modifier = Modifier.padding(horizontal = 24.dp)) {
Row(
modifier = Modifier
.horizontalScroll(scrollState)
) {
for (i in startValue..endValue step step) {
RulerSection(
number = i,
step,
sliderValue,
angleSliderValue,
colorSliderValue
)
}
}
ValueDisplay(value = currentValue, isAnimating)
}
}
}
}
@Composable
fun SliderControl(
label: String,
value: Float,
valueRange: ClosedFloatingPointRange<Float>,
onValueChange: (Float) -> Unit
) {
Text(label)
Slider(
value = value,
onValueChange = onValueChange,
valueRange = valueRange
)
}
@Composable
fun RulerSection(number: Int, step: Int, sliderValue: Float, angle: Float, colorValue: Float) {
val mainColor = Color(0xFF6200EE)
val secondaryColor = Color(0xFF03DAC5)
val interpolatedColor = lerp(mainColor, secondaryColor, colorValue)
Column(horizontalAlignment = Alignment.CenterHorizontally) {
Text(
text = number.toString(),
fontSize = 18.sp,
textAlign = TextAlign.Center,
modifier = Modifier.padding(vertical = 8.dp)
)
Canvas(
modifier = Modifier
.height(50.dp)
.width(80.dp)
) {
val angleRadians = Math.toRadians(angle.toDouble()).toFloat()
val bigLineHeight = 20f * sliderValue
val bigLineX = size.width / 2
drawLine(
color = interpolatedColor,
start = Offset(x = bigLineX, y = 0f),
end = Offset(
x = bigLineX + bigLineHeight * sin(angleRadians),
y = bigLineHeight * cos(angleRadians)
),
strokeWidth = 7f * sliderValue
)
val totalSmallLines = 4
val smallLineHeight = 10f * sliderValue
val smallLineStrokeWidth = 2f * sliderValue
val availableWidth = size.width - (4f * 2)
val interval = availableWidth / (totalSmallLines + 1)
for (i in 1..totalSmallLines) {
val xPosition = bigLineX + (interval * i)
drawLine(
color = interpolatedColor.copy(alpha = 0.5f),
start = Offset(x = xPosition, y = 0f),
end = Offset(
x = xPosition + smallLineHeight * sin(angleRadians),
y = smallLineHeight * cos(angleRadians)
),
strokeWidth = smallLineStrokeWidth
)
}
}
}
}
@Composable
fun ValueDisplay(value: Int, isAnimating: Boolean, maxValue: Int = 100) {
Box(
modifier = Modifier
.padding(top = 40.dp)
.fillMaxWidth()
.height(50.dp)
) {
val animatedLineLength = animateFloatAsState(
targetValue = if (isAnimating) value.toFloat() / maxValue else 0f,
animationSpec = spring(), label = "animatedLineLength"
)
Canvas(
modifier = Modifier
.fillMaxWidth()
.height(10.dp)
) {
drawLineWithAnimation(this, animatedLineLength.value)
}
}
}
fun drawLineWithAnimation(drawScope: DrawScope, fraction: Float) {
val lineLength = fraction * drawScope.size.width * 2.2f
drawScope.drawLine(
brush = Brush.linearGradient(listOf(Color.Red.copy(alpha = 0.5f), Color.Red)),
start = Offset(x = 0f, y = 0f),
end = Offset(x = lineLength, y = 0f),
strokeWidth = 8f
)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment