@@ -6,7 +6,11 @@ import androidx.compose.animation.core.animateDpAsState
66import androidx.compose.animation.core.spring
77import androidx.compose.animation.core.tween
88import 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
912import androidx.compose.foundation.gestures.detectHorizontalDragGestures
13+ import androidx.compose.foundation.gestures.waitForUpOrCancellation
1014import androidx.compose.foundation.layout.padding
1115import androidx.compose.foundation.layout.requiredSize
1216import 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