Reputation: 123
I have a SwipeToDismiss
instance to delete items with dismissThresholds
75%.
If user swipes row too fast without reaching 75% threshold the row being deleted. How to prevent that?
Here is code where I execute an action:
val dismissState = rememberDismissState(
confirmStateChange = {
if (it == DismissValue.DismissedToStart) {
viewModel.deleteCity(city)
}
true
}
)
Upvotes: 5
Views: 3450
Reputation: 2571
A less intrusive version based on Nucifera's solution, without touching the background { }
:
const val Threshold = 0.5f
var state: SwipeToDismissBoxState? = null // workaround for the recursive reference
state = rememberSwipeToDismissBoxState(
positionalThreshold = {
it * Threshold
},
confirmValueChange = {
if (it == EndToStart && state!!.progress > Threshold) {
// ...
true
} else {
false
}
}
)
Upvotes: 1
Reputation: 61
I ran into the same issue and found a fix that works for me. My theory is, that when the swipe is very fast but doesn't go very far (doesn't reach the set fractional threshold), the layout just immediately resets. In this case (DismissToStart), meaning the view snaps back to the right screen edge, giving us the value of 1.0f for the threshold and thus triggering the confirmStateChange because the fraction is per definition higher than our threshold. The problem being that our threshold is measured from the right screen edge, and this fracion (in my theory) is measured from the left screen edge.
So my solution is to track the current fractional value, and inside confirmStateChange
check if the current value is higher than the threshold, BUT NOT 1.0f. In a real world scenario, I think it's impossible to reach 1.0 with actual swiping the finger from right to left, so the solution seems safe to me.
val dismissThreshold = 0.25f
val currentFraction = remember { mutableStateOf(0f) }
val dismissState = rememberDismissState(
confirmStateChange = {
if (it == DismissValue.DismissedToStart) {
if (currentFraction.value >= dismissThreshold && currentFraction.value < 1.0f) {
onSwiped(item)
}
}
dismissOnSwipe
}
)
SwipeToDismiss(
state = dismissState,
modifier = Modifier.animateItemPlacement(),
directions = setOf(DismissDirection.EndToStart),
dismissThresholds = { direction ->
FractionalThreshold(dismissThreshold)
},
background = {
Box(...) {
currentFraction.value = dismissState.progress.fraction
...
}
}
dismissContent = {...}
)
Upvotes: 6
Reputation: 21
I'm dealing with the same issue, it seems to be a feature, not a bug, but I did not find the way to disable it.
*If the user has dragged their finger across over 50% of the screen width, the app should trigger the rest of the swipe back animation. If it's less than that, the app should snap back to the full app view.
If the gesture is quick, ignore the 50% threshold rule and swipe back.*
https://developer.android.com/training/wearables/compose/swipe-to-dismiss
Upvotes: 1