Skip to content

Commit 6ec6c1d

Browse files
committed
library: Optimize Switch touch behavior
1 parent 2b62b91 commit 6ec6c1d

File tree

1 file changed

+44
-46
lines changed
  • miuix/src/commonMain/kotlin/top/yukonga/miuix/kmp/basic

1 file changed

+44
-46
lines changed

miuix/src/commonMain/kotlin/top/yukonga/miuix/kmp/basic/Switch.kt

Lines changed: 44 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,11 @@ import androidx.compose.animation.core.animateDpAsState
66
import androidx.compose.animation.core.spring
77
import androidx.compose.animation.core.tween
88
import androidx.compose.foundation.background
9+
import androidx.compose.foundation.gestures.awaitEachGesture
10+
import androidx.compose.foundation.gestures.awaitFirstDown
11+
import androidx.compose.foundation.gestures.awaitVerticalTouchSlopOrCancellation
912
import androidx.compose.foundation.gestures.detectHorizontalDragGestures
13+
import androidx.compose.foundation.gestures.waitForUpOrCancellation
1014
import androidx.compose.foundation.layout.padding
1115
import androidx.compose.foundation.layout.requiredSize
1216
import androidx.compose.foundation.layout.size
@@ -62,14 +66,13 @@ fun Switch(
6266
)
6367
}
6468
var isPressed by remember { mutableStateOf(false) }
65-
var trackDragOffset by remember { mutableStateOf(0f) }
66-
var thumbDragOffset by remember { mutableStateOf(0f) }
69+
var dragOffset by remember { mutableStateOf(0f) }
6770
val thumbOffset by animateDpAsState(
6871
targetValue = if (isChecked) {
6972
if (!enabled) 26.dp else if (isPressed) 24.dp else 26.dp
7073
} else {
7174
if (!enabled) 4.dp else if (isPressed) 3.dp else 4.dp
72-
} + thumbDragOffset.dp,
75+
} + dragOffset.dp,
7376
animationSpec = springSpec
7477
)
7578

@@ -113,22 +116,33 @@ fun Switch(
113116
.clip(RoundedCornerShape(100.dp))
114117
.drawBehind { drawRect(backgroundColor) }
115118
.pointerInput(Unit) {
119+
if (!enabled) return@pointerInput
116120
detectHorizontalDragGestures(
121+
onDragStart = {
122+
isPressed = true
123+
hasVibrated = false
124+
},
117125
onDragEnd = {
118-
if (trackDragOffset != 0f) {
126+
isPressed = false
127+
val switchWidth = 21f
128+
if (dragOffset.absoluteValue > switchWidth / 2) {
119129
onCheckedChange?.invoke(!isChecked)
120-
if (thumbOffset == 4.dp || thumbOffset == 26.dp)
121-
hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress)
122130
}
123-
trackDragOffset = 0f
131+
dragOffset = 0f
124132
},
125133
onDragCancel = {
126-
trackDragOffset = 0f
134+
isPressed = false
135+
dragOffset = 0f
136+
}
137+
) { _, dragAmount ->
138+
val newOffset = dragOffset + dragAmount / 2
139+
dragOffset = if (isChecked) newOffset.coerceIn(-21f, 0f) else newOffset.coerceIn(0f, 21f)
140+
if (dragOffset in -20f..-1f || dragOffset in 1f..20f) {
141+
hasVibrated = false
142+
} else if ((dragOffset == -21f || dragOffset == 0f || dragOffset == 21f) && !hasVibrated) {
143+
hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress)
144+
hasVibrated = true
127145
}
128-
) { change, dragAmount ->
129-
if (!enabled) return@detectHorizontalDragGestures
130-
trackDragOffset = dragAmount
131-
change.consume()
132146
}
133147
}
134148
.then(toggleableModifier)
@@ -143,46 +157,30 @@ fun Switch(
143157
shape = RoundedCornerShape(100.dp)
144158
)
145159
.pointerInput(Unit) {
146-
detectHorizontalDragGestures(
147-
onDragStart = {
160+
if (!enabled) return@pointerInput
161+
awaitEachGesture {
162+
awaitFirstDown().also {
163+
it.consume()
148164
isPressed = true
149-
hasVibrated = false
150-
},
151-
onDragEnd = {
152-
isPressed = false
153-
val switchWidth = 21f
154-
if (thumbDragOffset.absoluteValue > switchWidth / 2) {
155-
onCheckedChange?.invoke(!isChecked)
156-
}
157-
thumbDragOffset = 0f
158-
},
159-
onDragCancel = {
165+
}
166+
waitForUpOrCancellation()?.also {
167+
it.consume()
160168
isPressed = false
161-
thumbDragOffset = 0f
169+
hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress)
170+
onCheckedChange?.invoke(!isChecked)
162171
}
163-
) { change, dragAmount ->
164-
if (!enabled) return@detectHorizontalDragGestures
165-
val newOffset = thumbDragOffset + dragAmount / 2
166-
thumbDragOffset =
167-
if (isChecked) newOffset.coerceIn(-21f, 0f) else newOffset.coerceIn(0f, 21f)
168-
if (isChecked) {
169-
if (thumbDragOffset in -20f..-1f) {
170-
hasVibrated = false
171-
} else if ((thumbDragOffset == -21f || thumbDragOffset == 0f) && !hasVibrated) {
172-
hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress)
173-
hasVibrated = true
174-
}
175-
} else {
176-
if (thumbDragOffset in 1f..20f) {
177-
hasVibrated = false
178-
} else if ((thumbDragOffset == 0f || thumbDragOffset == 21f) && !hasVibrated) {
179-
hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress)
180-
hasVibrated = true
181-
}
172+
}
173+
}
174+
.pointerInput(Unit) {
175+
if (!enabled) return@pointerInput
176+
awaitEachGesture {
177+
val down = awaitFirstDown(requireUnconsumed = false)
178+
awaitVerticalTouchSlopOrCancellation(down.id) { _, _ ->
179+
isPressed = false
182180
}
183-
change.consume()
184181
}
185182
}
183+
186184
)
187185
}
188186
}

0 commit comments

Comments
 (0)