Skip to content

Commit 66d1289

Browse files
fix #3
Change thumb movement gesture to drag and tap
1 parent 9a03401 commit 66d1289

File tree

2 files changed

+85
-68
lines changed

2 files changed

+85
-68
lines changed

slider/src/main/java/com/smarttoolfactory/slider/ColorfulIconSlider.kt

Lines changed: 48 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ package com.smarttoolfactory.slider
22

33
import androidx.compose.foundation.BorderStroke
44
import androidx.compose.foundation.Canvas
5+
import androidx.compose.foundation.gestures.detectDragGestures
6+
import androidx.compose.foundation.gestures.detectTapGestures
57
import androidx.compose.foundation.layout.*
68
import androidx.compose.runtime.Composable
79
import androidx.compose.runtime.mutableStateOf
@@ -14,12 +16,13 @@ import androidx.compose.ui.geometry.Offset
1416
import androidx.compose.ui.geometry.Size
1517
import androidx.compose.ui.graphics.*
1618
import androidx.compose.ui.graphics.drawscope.Stroke
19+
import androidx.compose.ui.input.pointer.PointerInputChange
20+
import androidx.compose.ui.input.pointer.pointerInput
1721
import androidx.compose.ui.layout.Placeable
1822
import androidx.compose.ui.layout.SubcomposeLayout
1923
import androidx.compose.ui.platform.LocalDensity
2024
import androidx.compose.ui.platform.LocalLayoutDirection
2125
import 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

slider/src/main/java/com/smarttoolfactory/slider/ColorfulSlider.kt

Lines changed: 37 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ package com.smarttoolfactory.slider
33
import androidx.compose.foundation.BorderStroke
44
import androidx.compose.foundation.Canvas
55
import androidx.compose.foundation.background
6+
import androidx.compose.foundation.gestures.detectDragGestures
7+
import androidx.compose.foundation.gestures.detectTapGestures
68
import androidx.compose.foundation.layout.*
79
import androidx.compose.foundation.shape.CircleShape
810
import androidx.compose.runtime.*
@@ -15,13 +17,14 @@ import androidx.compose.ui.geometry.Size
1517
import androidx.compose.ui.geometry.lerp
1618
import androidx.compose.ui.graphics.*
1719
import androidx.compose.ui.graphics.drawscope.Stroke
20+
import androidx.compose.ui.input.pointer.PointerInputChange
21+
import androidx.compose.ui.input.pointer.pointerInput
1822
import androidx.compose.ui.platform.LocalDensity
1923
import androidx.compose.ui.platform.LocalLayoutDirection
2024
import androidx.compose.ui.unit.Dp
2125
import androidx.compose.ui.unit.IntOffset
2226
import androidx.compose.ui.unit.LayoutDirection
2327
import androidx.compose.ui.unit.dp
24-
import com.smarttoolfactory.gesture.pointerMotionEvents
2528
import kotlin.math.abs
2629

2730
/**
@@ -213,37 +216,41 @@ fun ColorfulSlider(
213216
val coerced = value.coerceIn(valueRange.start, valueRange.endInclusive)
214217
val fraction = calculateFraction(valueRange.start, valueRange.endInclusive, coerced)
215218

216-
val dragModifier = Modifier.pointerMotionEvents(
217-
onDown = {
218-
if (enabled) {
219-
rawOffset.value = if (!isRtl) it.position.x else trackEnd - it.position.x
220-
val offsetInTrack = rawOffset.value.coerceIn(trackStart, trackEnd)
221-
onValueChangeState.value.invoke(
222-
scaleToUserValue(offsetInTrack),
223-
Offset(rawOffset.value.coerceIn(trackStart, trackEnd), strokeRadius)
224-
)
225-
it.consume()
226-
}
227-
},
228-
onMove = {
229-
if (enabled) {
230-
rawOffset.value = if (!isRtl) it.position.x else trackEnd - it.position.x
231-
val offsetInTrack = rawOffset.value.coerceIn(trackStart, trackEnd)
232-
onValueChangeState.value.invoke(
233-
scaleToUserValue(offsetInTrack),
234-
Offset(rawOffset.value.coerceIn(trackStart, trackEnd), strokeRadius)
235-
)
236-
it.consume()
237-
}
238-
239-
},
240-
onUp = {
241-
if (enabled) {
242-
onValueChangeFinished?.invoke()
243-
it.consume()
219+
val dragModifier = Modifier
220+
.pointerInput(Unit) {
221+
detectDragGestures(
222+
onDrag = { change: PointerInputChange, _: Offset ->
223+
if (enabled) {
224+
rawOffset.value =
225+
if (!isRtl) change.position.x else trackEnd - change.position.x
226+
val offsetInTrack = rawOffset.value.coerceIn(trackStart, trackEnd)
227+
onValueChangeState.value.invoke(
228+
scaleToUserValue(offsetInTrack),
229+
Offset(rawOffset.value.coerceIn(trackStart, trackEnd), strokeRadius)
230+
)
231+
}
232+
233+
},
234+
onDragEnd = {
235+
if (enabled) {
236+
onValueChangeFinished?.invoke()
237+
}
238+
}
239+
)
240+
}
241+
.pointerInput(Unit) {
242+
detectTapGestures { position: Offset ->
243+
if (enabled) {
244+
rawOffset.value =
245+
if (!isRtl) position.x else trackEnd - position.x
246+
val offsetInTrack = rawOffset.value.coerceIn(trackStart, trackEnd)
247+
onValueChangeState.value.invoke(
248+
scaleToUserValue(offsetInTrack),
249+
Offset(rawOffset.value.coerceIn(trackStart, trackEnd), strokeRadius)
250+
)
251+
}
244252
}
245253
}
246-
)
247254

248255
SliderImpl(
249256
enabled = enabled,

0 commit comments

Comments
 (0)