-
Notifications
You must be signed in to change notification settings - Fork 4.7k
/
PinchGestureHandler.kt
96 lines (86 loc) · 2.8 KB
/
PinchGestureHandler.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
package com.swmansion.gesturehandler
import android.graphics.PointF
import android.view.MotionEvent
import android.view.ViewConfiguration
import kotlin.math.abs
class PinchGestureHandler : GestureHandler<PinchGestureHandler>() {
var scale = 0.0
private set
var velocity = 0.0
private set
var focalPointX: Float = Float.NaN
private set
var focalPointY: Float = Float.NaN
private set
private var scaleGestureDetector: ScaleGestureDetector? = null
private var startingSpan = 0f
private var spanSlop = 0f
private val gestureListener: ScaleGestureDetector.OnScaleGestureListener = object : ScaleGestureDetector.OnScaleGestureListener {
override fun onScale(detector: ScaleGestureDetector): Boolean {
val prevScaleFactor: Double = scale
scale *= detector.scaleFactor.toDouble()
val delta = detector.timeDelta
if (delta > 0) {
velocity = (scale - prevScaleFactor) / delta
}
if (abs(startingSpan - detector.currentSpan) >= spanSlop
&& state == STATE_BEGAN) {
activate()
}
return true
}
init {
setShouldCancelWhenOutside(false)
}
override fun onScaleBegin(detector: ScaleGestureDetector): Boolean {
startingSpan = detector.currentSpan
return true
}
override fun onScaleEnd(detector: ScaleGestureDetector) {
// ScaleGestureDetector thinks that when fingers are 27mm away that's a sufficiently good
// reason to trigger this method giving us no other choice but to ignore it completely.
}
}
override fun onHandle(event: MotionEvent, sourceEvent: MotionEvent) {
if (state == STATE_UNDETERMINED) {
val context = view!!.context
resetProgress()
scaleGestureDetector = ScaleGestureDetector(context, gestureListener)
val configuration = ViewConfiguration.get(context)
spanSlop = configuration.scaledTouchSlop.toFloat()
begin()
}
scaleGestureDetector?.onTouchEvent(sourceEvent)
scaleGestureDetector?.let {
val point = transformPoint(PointF(it.focusX, it.focusY))
this.focalPointX = point.x
this.focalPointY = point.y
}
var activePointers = sourceEvent.pointerCount
if (sourceEvent.actionMasked == MotionEvent.ACTION_POINTER_UP) {
activePointers -= 1
}
if (state == STATE_ACTIVE && activePointers < 2) {
end()
} else if (sourceEvent.actionMasked == MotionEvent.ACTION_UP) {
fail()
}
}
override fun activate(force: Boolean) {
// reset scale if the handler has not yet activated
if (state != STATE_ACTIVE) {
resetProgress()
}
super.activate(force)
}
override fun onReset() {
scaleGestureDetector = null
focalPointX = Float.NaN
focalPointY = Float.NaN
resetProgress()
}
override fun resetProgress() {
velocity = 0.0
scale = 1.0
}
}