lmw
2025-04-24 718f31c92e2029d05260810435a2c70cef6e6ce5
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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
package cn.sinata.xldutils.view.gesture
 
import android.view.MotionEvent
 
/**
 * Component that detects and tracks multiple pointers based on touch events.
 *
 *
 * Each time a pointer gets pressed or released, the current gesture (if any) will end, and a new
 * one will be started (if there are still pressed pointers left). It is guaranteed that the number
 * of pointers within the single gesture will remain the same during the whole gesture.
 */
open class MultiPointerGestureDetector {
 
    /** The listener for receiving notifications when gestures occur.  */
    interface Listener {
        /** Responds to the beginning of a gesture.  */
        fun onGestureBegin(detector: MultiPointerGestureDetector)
 
        /** Responds to the update of a gesture in progress.  */
        fun onGestureUpdate(detector: MultiPointerGestureDetector)
 
        /** Responds to the end of a gesture.  */
        fun onGestureEnd(detector: MultiPointerGestureDetector)
    }
 
    /** Gets whether gesture is in progress or not  */
    var isGestureInProgress: Boolean = false
        private set
    /** Gets the number of pointers in the current gesture  */
    var count: Int = 0
        private set
    private val mId = IntArray(MAX_POINTERS)
    /**
     * Gets the start X coordinates for the all pointers
     * Mutable array is exposed for performance reasons and is not to be modified by the callers.
     */
    val startX = FloatArray(MAX_POINTERS)
    /**
     * Gets the start Y coordinates for the all pointers
     * Mutable array is exposed for performance reasons and is not to be modified by the callers.
     */
    val startY = FloatArray(MAX_POINTERS)
    /**
     * Gets the current X coordinates for the all pointers
     * Mutable array is exposed for performance reasons and is not to be modified by the callers.
     */
    val currentX = FloatArray(MAX_POINTERS)
    /**
     * Gets the current Y coordinates for the all pointers
     * Mutable array is exposed for performance reasons and is not to be modified by the callers.
     */
    val currentY = FloatArray(MAX_POINTERS)
 
    private var mListener: Listener? = null
 
    init {
        reset()
    }
 
    /**
     * Sets the listener.
     * @param listener listener to set
     */
    fun setListener(listener: Listener) {
        mListener = listener
    }
 
    /**
     * Resets the component to the initial state.
     */
    fun reset() {
        isGestureInProgress = false
        count = 0
        for (i in 0..MAX_POINTERS - 1) {
            mId[i] = MotionEvent.INVALID_POINTER_ID
        }
    }
 
    /**
     * This method can be overridden in order to perform threshold check or something similar.
     * @return whether or not to start a new gesture
     */
    protected fun shouldStartGesture(): Boolean {
        return true
    }
 
    private fun startGesture() {
        if (!isGestureInProgress) {
            isGestureInProgress = true
            if (mListener != null) {
                mListener!!.onGestureBegin(this)
            }
        }
    }
 
    private fun stopGesture() {
        if (isGestureInProgress) {
            isGestureInProgress = false
            if (mListener != null) {
                mListener!!.onGestureEnd(this)
            }
        }
    }
 
    /**
     * Gets the index of the i-th pressed pointer.
     * Normally, the index will be equal to i, except in the case when the pointer is released.
     * @return index of the specified pointer or -1 if not found (i.e. not enough pointers are down)
     */
    private fun getPressedPointerIndex(event: MotionEvent,i: Int): Int {
        var pIndex = i
        val count = event.pointerCount
        val action = event.actionMasked
        val index = event.actionIndex
        if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_POINTER_UP) {
            if (pIndex >= index) {
                pIndex++
            }
        }
        return if (pIndex < count) pIndex else -1
    }
 
    /**
     * Handles the given motion event.
     * @param event event to handle
     * *
     * @return whether or not the event was handled
     */
    fun onTouchEvent(event: MotionEvent): Boolean {
        when (event.actionMasked) {
            MotionEvent.ACTION_MOVE -> {
                // update pointers
                for (i in 0..MAX_POINTERS - 1) {
                    val index = event.findPointerIndex(mId[i])
                    if (index != -1) {
                        currentX[i] = event.getX(index)
                        currentY[i] = event.getY(index)
                    }
                }
                // start a new gesture if not already started
                if (!isGestureInProgress && shouldStartGesture()) {
                    startGesture()
                }
                // notify listener
                if (isGestureInProgress && mListener != null) {
                    mListener!!.onGestureUpdate(this)
                }
            }
 
            MotionEvent.ACTION_DOWN, MotionEvent.ACTION_POINTER_DOWN, MotionEvent.ACTION_POINTER_UP, MotionEvent.ACTION_UP -> {
                run {
                    // we'll restart the current gesture (if any) whenever the number of pointers changes
                    // NOTE: we only restart existing gestures here, new gestures are started in ACTION_MOVE
                    val wasGestureInProgress = isGestureInProgress
                    stopGesture()
                    reset()
                    // update pointers
                    for (i in 0..MAX_POINTERS - 1) {
                        val index = getPressedPointerIndex(event, i)
                        if (index == -1) {
                            break
                        }
                        mId[i] = event.getPointerId(index)
                        startX[i] = event.getX(index)
                        currentX[i] = startX[i]
                        startY[i] = event.getY(index)
                        currentY[i] = startY[i]
                        count++
                    }
                    // restart the gesture (if any) if there are still pointers left
                    if (wasGestureInProgress && count > 0) {
                        startGesture()
                        return true
                    } else {
                        //处理click事件
                        if (!wasGestureInProgress) {
                            return false
                        }
                    }
 
                    //        break;
                }
                run {
                    stopGesture()
                    reset()
                }
            }
 
            MotionEvent.ACTION_CANCEL -> {
                stopGesture()
                reset()
            }
        }
        return true
    }
 
    /** Restarts the current gesture  */
    fun restartGesture() {
        if (!isGestureInProgress) {
            return
        }
        stopGesture()
        for (i in 0..MAX_POINTERS - 1) {
            startX[i] = currentX[i]
            startY[i] = currentY[i]
        }
        startGesture()
    }
 
    companion object {
 
        private val MAX_POINTERS = 2
 
        /** Factory method that creates a new instance of MultiPointerGestureDetector  */
        fun newInstance(): MultiPointerGestureDetector {
            return MultiPointerGestureDetector()
        }
    }
}