-
-
Notifications
You must be signed in to change notification settings - Fork 986
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Make FlingHandler use velocity as the activation metric. (#2796)
## Description Fixed fling component handler to activate based on fling velocity instead of fling distance. The fling also no longer has to be performed from start to finish entirely within the component's bounds. This feature was tested on both emulated and live android phones. ## Test plan - clone this branch - run `yarn` - go to `example` - copy fling example from the docs into the `example/src/empty/EmptyExample.tsx` file ### Web - run `yarn start` ### Android - go to `example/android` - run `yarn start` ### IOS - IOS remains unchanged, it already implements this mechanism in a different way. ## Reference https://github.com/software-mansion/react-native-gesture-handler/assets/74246391/6868ff68-4e6e-41fb-93a7-0cd35e85cd6e --------- Co-authored-by: Michał Bert <[email protected]> Co-authored-by: Jakub Piasecki <[email protected]>
- Loading branch information
1 parent
08c921a
commit 3904238
Showing
5 changed files
with
195 additions
and
55 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
56 changes: 56 additions & 0 deletions
56
android/src/main/java/com/swmansion/gesturehandler/core/Vector.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
package com.swmansion.gesturehandler.core | ||
|
||
import android.view.VelocityTracker | ||
import com.swmansion.gesturehandler.core.GestureHandler.Companion.DIRECTION_DOWN | ||
import com.swmansion.gesturehandler.core.GestureHandler.Companion.DIRECTION_LEFT | ||
import com.swmansion.gesturehandler.core.GestureHandler.Companion.DIRECTION_RIGHT | ||
import com.swmansion.gesturehandler.core.GestureHandler.Companion.DIRECTION_UP | ||
import kotlin.math.hypot | ||
|
||
class Vector(val x: Double, val y: Double) { | ||
private val unitX: Double | ||
private val unitY: Double | ||
val magnitude = hypot(x, y) | ||
|
||
init { | ||
val isMagnitudeSufficient = magnitude > MINIMAL_MAGNITUDE | ||
|
||
unitX = if (isMagnitudeSufficient) x / magnitude else 0.0 | ||
unitY = if (isMagnitudeSufficient) y / magnitude else 0.0 | ||
} | ||
|
||
private fun computeSimilarity(vector: Vector): Double { | ||
return unitX * vector.unitX + unitY * vector.unitY | ||
} | ||
|
||
fun isSimilar(vector: Vector, threshold: Double): Boolean { | ||
return computeSimilarity(vector) > threshold | ||
} | ||
|
||
companion object { | ||
private val VECTOR_LEFT: Vector = Vector(-1.0, 0.0) | ||
private val VECTOR_RIGHT: Vector = Vector(1.0, 0.0) | ||
private val VECTOR_UP: Vector = Vector(0.0, -1.0) | ||
private val VECTOR_DOWN: Vector = Vector(0.0, 1.0) | ||
private val VECTOR_ZERO: Vector = Vector(0.0, 0.0) | ||
const val MINIMAL_MAGNITUDE = 0.1 | ||
|
||
fun fromDirection(direction: Int): Vector = | ||
when (direction) { | ||
DIRECTION_LEFT -> VECTOR_LEFT | ||
DIRECTION_RIGHT -> VECTOR_RIGHT | ||
DIRECTION_UP -> VECTOR_UP | ||
DIRECTION_DOWN -> VECTOR_DOWN | ||
else -> VECTOR_ZERO | ||
} | ||
|
||
fun fromVelocity(tracker: VelocityTracker): Vector { | ||
tracker.computeCurrentVelocity(1000) | ||
|
||
val velocityX = tracker.xVelocity.toDouble() | ||
val velocityY = tracker.yVelocity.toDouble() | ||
|
||
return Vector(velocityX, velocityY) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,2 @@ | ||
export const DEFAULT_TOUCH_SLOP = 15; | ||
|
||
export const Direction = { | ||
RIGHT: 1, | ||
LEFT: 2, | ||
UP: 4, | ||
DOWN: 8, | ||
}; | ||
export const MINIMAL_FLING_VELOCITY = 0.1; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
import { Directions } from '../../Directions'; | ||
import { MINIMAL_FLING_VELOCITY } from '../constants'; | ||
import PointerTracker from './PointerTracker'; | ||
|
||
export default class Vector { | ||
private readonly x; | ||
private readonly y; | ||
private readonly unitX; | ||
private readonly unitY; | ||
private readonly _magnitude; | ||
|
||
constructor(x: number, y: number) { | ||
this.x = x; | ||
this.y = y; | ||
|
||
this._magnitude = Math.hypot(this.x, this.y); | ||
const isMagnitudeSufficient = this._magnitude > MINIMAL_FLING_VELOCITY; | ||
|
||
this.unitX = isMagnitudeSufficient ? this.x / this._magnitude : 0; | ||
this.unitY = isMagnitudeSufficient ? this.y / this._magnitude : 0; | ||
} | ||
|
||
static fromDirection(direction: Directions) { | ||
return DirectionToVectorMappings.get(direction)!; | ||
} | ||
|
||
static fromVelocity(tracker: PointerTracker, pointerId: number) { | ||
return new Vector( | ||
tracker.getVelocityX(pointerId), | ||
tracker.getVelocityY(pointerId) | ||
); | ||
} | ||
|
||
get magnitude() { | ||
return this._magnitude; | ||
} | ||
|
||
computeSimilarity(vector: Vector) { | ||
return this.unitX * vector.unitX + this.unitY * vector.unitY; | ||
} | ||
|
||
isSimilar(vector: Vector, threshold: number) { | ||
return this.computeSimilarity(vector) > threshold; | ||
} | ||
} | ||
|
||
const DirectionToVectorMappings = new Map<Directions, Vector>([ | ||
[Directions.LEFT, new Vector(-1, 0)], | ||
[Directions.RIGHT, new Vector(1, 0)], | ||
[Directions.UP, new Vector(0, -1)], | ||
[Directions.DOWN, new Vector(0, 1)], | ||
]); |