@@ -2,6 +2,8 @@ package com.smarttoolfactory.slider
22
33import androidx.compose.foundation.BorderStroke
44import androidx.compose.foundation.Canvas
5+ import androidx.compose.foundation.gestures.detectDragGestures
6+ import androidx.compose.foundation.gestures.detectTapGestures
57import androidx.compose.foundation.layout.*
68import androidx.compose.runtime.Composable
79import androidx.compose.runtime.mutableStateOf
@@ -14,12 +16,13 @@ import androidx.compose.ui.geometry.Offset
1416import androidx.compose.ui.geometry.Size
1517import androidx.compose.ui.graphics.*
1618import androidx.compose.ui.graphics.drawscope.Stroke
19+ import androidx.compose.ui.input.pointer.PointerInputChange
20+ import androidx.compose.ui.input.pointer.pointerInput
1721import androidx.compose.ui.layout.Placeable
1822import androidx.compose.ui.layout.SubcomposeLayout
1923import androidx.compose.ui.platform.LocalDensity
2024import androidx.compose.ui.platform.LocalLayoutDirection
2125import androidx.compose.ui.unit.*
22- import com.smarttoolfactory.gesture.pointerMotionEvents
2326
2427/* *
2528 * Material Slider allows to choose height for track and thumb radius and selection between
@@ -151,7 +154,8 @@ fun ColorfulIconSlider(
151154 val isRtl = LocalLayoutDirection .current == LayoutDirection .Rtl
152155
153156 val width = constraints.maxWidth.toFloat()
154- val thumbRadiusInPx = (thumbSize.width / 2 ).toFloat()
157+ val thumbHalfWidthPx = (thumbSize.width / 2 ).toFloat()
158+ val thumbHeightPx = thumbSize.height.toFloat()
155159
156160 // Start of the track used for measuring progress,
157161 // it's line + radius of cap which is half of height of track
@@ -164,11 +168,11 @@ fun ColorfulIconSlider(
164168 with (LocalDensity .current) {
165169
166170 strokeRadius = trackHeight.toPx() / 2
167- trackStart = thumbRadiusInPx .coerceAtLeast(strokeRadius)
171+ trackStart = thumbHalfWidthPx .coerceAtLeast(strokeRadius)
168172 trackEnd = width - trackStart
169173 }
170174
171- // Sales and interpolates from offset from dragging to user value in valueRange
175+ // Scales and interpolates from offset from dragging to user value in valueRange
172176 fun scaleToUserValue (offset : Float ) =
173177 scale(trackStart, trackEnd, offset, valueRange.start, valueRange.endInclusive)
174178
@@ -189,37 +193,41 @@ fun ColorfulIconSlider(
189193 val coerced = value.coerceIn(valueRange.start, valueRange.endInclusive)
190194 val fraction = calculateFraction(valueRange.start, valueRange.endInclusive, coerced)
191195
192- val dragModifier = Modifier .pointerMotionEvents(
193- onDown = {
194- if (enabled) {
195- rawOffset.value = if (! isRtl) it.position.x else trackEnd - it.position.x
196- val offsetInTrack = rawOffset.value.coerceIn(trackStart, trackEnd)
197- onValueChangeState.value.invoke(
198- scaleToUserValue(offsetInTrack),
199- Offset (rawOffset.value.coerceIn(trackStart, trackEnd), strokeRadius)
200- )
201- it.consume()
202- }
203- },
204- onMove = {
205- if (enabled) {
206- rawOffset.value = if (! isRtl) it.position.x else trackEnd - it.position.x
207- val offsetInTrack = rawOffset.value.coerceIn(trackStart, trackEnd)
208- onValueChangeState.value.invoke(
209- scaleToUserValue(offsetInTrack),
210- Offset (rawOffset.value.coerceIn(trackStart, trackEnd), strokeRadius)
211- )
212- it.consume()
213- }
214-
215- },
216- onUp = {
217- if (enabled) {
218- onValueChangeFinished?.invoke()
219- it.consume()
196+ val dragModifier = Modifier
197+ .pointerInput(Unit ) {
198+ detectDragGestures(
199+ onDrag = { change: PointerInputChange , _: Offset ->
200+ if (enabled) {
201+ rawOffset.value =
202+ if (! isRtl) change.position.x else trackEnd - change.position.x
203+ val offsetInTrack = rawOffset.value.coerceIn(trackStart, trackEnd)
204+ onValueChangeState.value.invoke(
205+ scaleToUserValue(offsetInTrack),
206+ Offset (rawOffset.value.coerceIn(trackStart, trackEnd), strokeRadius)
207+ )
208+ }
209+
210+ },
211+ onDragEnd = {
212+ if (enabled) {
213+ onValueChangeFinished?.invoke()
214+ }
215+ }
216+ )
217+ }
218+ .pointerInput(Unit ) {
219+ detectTapGestures { position: Offset ->
220+ if (enabled) {
221+ rawOffset.value =
222+ if (! isRtl) position.x else trackEnd - position.x
223+ val offsetInTrack = rawOffset.value.coerceIn(trackStart, trackEnd)
224+ onValueChangeState.value.invoke(
225+ scaleToUserValue(offsetInTrack),
226+ Offset (rawOffset.value.coerceIn(trackStart, trackEnd), strokeRadius)
227+ )
228+ }
220229 }
221230 }
222- )
223231
224232 IconSliderImpl (
225233 enabled = enabled,
@@ -229,7 +237,8 @@ fun ColorfulIconSlider(
229237 tickFractions = tickFractions,
230238 colors = colors,
231239 trackHeight = trackHeight,
232- thumbRadius = thumbRadiusInPx,
240+ thumbRadius = thumbHalfWidthPx,
241+ thumbHeight = thumbHeightPx,
233242 thumb = thumb,
234243 coerceThumbInTrack = coerceThumbInTrack,
235244 drawInactiveTrack = drawInactiveTrack,
@@ -250,22 +259,23 @@ private fun IconSliderImpl(
250259 colors : MaterialSliderColors ,
251260 trackHeight : Dp ,
252261 thumbRadius : Float ,
262+ thumbHeight : Float ,
253263 thumb : @Composable () -> Unit ,
254264 coerceThumbInTrack : Boolean ,
255265 drawInactiveTrack : Boolean ,
256266 borderStroke : BorderStroke ? = null,
257- modifier : Modifier ,
267+ modifier : Modifier
258268) {
259269
260270 val trackStrokeWidth: Float
261271
262272 var borderWidth = 0f
263273 val borderBrush: Brush ? = borderStroke?.brush
264- val thumbSize : Dp
274+ val thumbHeightDp : Dp
265275
266276 with (LocalDensity .current) {
267277 trackStrokeWidth = trackHeight.toPx()
268- thumbSize = (2 * thumbRadius).toDp()
278+ thumbHeightDp = (2 * thumbRadius.coerceAtLeast(thumbHeight) ).toDp()
269279
270280 if (borderStroke != null ) {
271281 borderWidth = borderStroke.width.toPx()
@@ -276,7 +286,7 @@ private fun IconSliderImpl(
276286 // Constraint max height of Slider to max of thumb or track or minimum touch 48.dp
277287 modifier.heightIn(
278288 max = trackHeight
279- .coerceAtLeast(thumbSize )
289+ .coerceAtLeast(thumbHeightDp )
280290 .coerceAtLeast(TrackHeight )
281291 ),
282292 contentAlignment = Alignment .CenterStart
0 commit comments