11package me.nishant.sliding_bar
22
3- import androidx.compose.material.Text
4- import androidx.compose.runtime.Composable
3+ import android.content.res.Resources
4+ import android.util.Log
5+ import android.util.TypedValue
6+ import android.view.MotionEvent
7+ import androidx.compose.animation.core.animateDpAsState
8+ import androidx.compose.foundation.Canvas
9+ import androidx.compose.runtime.*
10+ import androidx.compose.ui.ExperimentalComposeUiApi
11+ import androidx.compose.ui.Modifier
12+ import androidx.compose.ui.geometry.Offset
13+ import androidx.compose.ui.geometry.Size
14+ import androidx.compose.ui.input.pointer.pointerInteropFilter
15+ import androidx.compose.ui.unit.Dp
16+ import androidx.compose.ui.unit.dp
17+ import kotlin.math.abs
518
19+ @ExperimentalComposeUiApi
620@Composable
7- fun SlidingBar () {
8- Text (text = " Hello There!" )
9- }
21+ fun SlidingBar (
22+ value : Float ,
23+ onValueChanged : (Float ) -> Unit ,
24+ modifier : Modifier = Modifier ,
25+ enabled : Boolean = true,
26+ valueRange : ClosedFloatingPointRange <Float > = 0f..1f,
27+ stepSize : Float = 0.01f,
28+ colors : SlidingBarColors = SlidingBarDefaults .colors()
29+ ) {
30+ var pressed by remember { mutableStateOf(false ) }
31+ val radius by animateDpAsState(targetValue = if (pressed) 20 .dp else 0 .dp)
32+ var canvasSize by remember { mutableStateOf(Size (0f , 0f )) }
33+ var downX by remember { mutableStateOf(0f ) }
34+
35+ Canvas (
36+ modifier = modifier
37+ .pointerInteropFilter {
38+ val range = valueRange.endInclusive - valueRange.start
39+ val threshold = canvasSize.width / (range / stepSize)
40+ when (it.action) {
41+ MotionEvent .ACTION_DOWN -> {
42+ if (! enabled)
43+ return @pointerInteropFilter false
44+
45+ val point = Offset (
46+ (value - valueRange.start) / (valueRange.endInclusive - valueRange.start) * canvasSize.width,
47+ canvasSize.height / 2f
48+ )
49+ if (it.x in (point.x - toPx(12 .dp)).. (point.x + toPx(12 .dp)) &&
50+ it.y in (point.y - toPx(12 .dp)).. (point.y + toPx(12 .dp))
51+ ) {
52+ pressed = true
53+ downX = it.x
54+ true
55+ } else false
56+ }
57+ MotionEvent .ACTION_MOVE -> {
58+ val dx = it.x - downX
59+ Log .d(" my_debug" , " Slider: dx = $dx " )
60+ Log .d(" my_debug" , " Slider: threshold = $threshold " )
61+ if (abs(dx) >= threshold) {
62+ val newValue = if (dx > 0 ) value + stepSize else value - stepSize
63+ if (newValue in valueRange) {
64+ Log .d(" my_debug" , " Slider: newValue = $newValue " )
65+ onValueChanged(newValue)
66+ downX = it.x
67+ }
68+ }
69+ true
70+ }
71+ MotionEvent .ACTION_UP -> {
72+ downX = 0f
73+ pressed = false
74+ true
75+ }
76+ else -> false
77+ }
78+ }
79+ ) {
80+ canvasSize = size
81+ val (width) = size
82+ val point = Offset (
83+ (value - valueRange.start) / (valueRange.endInclusive - valueRange.start) * width,
84+ center.y
85+ )
86+ drawCircle(
87+ color = colors.colorPrimary,
88+ radius = radius.toPx(),
89+ center = point,
90+ alpha = 0.2f
91+ )
92+ drawLine(
93+ color = colors.colorTrack,
94+ start = Offset (0f , center.y),
95+ end = Offset (width, center.y),
96+ strokeWidth = 2 .dp.toPx(),
97+ alpha = 0.5f
98+ )
99+ drawLine(
100+ color = colors.colorTrack,
101+ start = Offset (0f , center.y),
102+ end = point,
103+ strokeWidth = 2 .dp.toPx()
104+ )
105+ drawCircle(
106+ color = colors.colorPrimary,
107+ radius = 12 .dp.toPx(),
108+ center = point
109+ )
110+ }
111+ }
112+
113+ private fun toPx (dp : Dp ) =
114+ TypedValue .applyDimension(
115+ TypedValue .COMPLEX_UNIT_DIP ,
116+ dp.value,
117+ Resources .getSystem().displayMetrics
118+ )
119+
0 commit comments