触摸事件类型
单点触控相关:
- ACTION_DOWN
当用户首次触摸屏幕时触发,表示触摸的开始。通常是触摸事件的起点。 - ACTION_MOVE
当用户在屏幕上移动手指时触发,表示触摸点位置发生变化。 - ACTION_UP
当用户抬起手指时触发,表示触摸结束。 - ACTION_CANCEL
当触摸事件被取消时触发,例如父 View 拦截了事件或系统中止了触摸。
多点触控相关:
- ACTION_POINTER_DOWN
当屏幕上已有触摸点时,另一个手指按下触发,表示新增了一个触摸点。 - ACTION_POINTER_UP
当屏幕上有多个触摸点时,其中一个手指抬起触发,表示某个触摸点结束。
多点触控处理相关方法
- event.getActionMasked():返回当前的触摸事件类型(包含单点触控和多点触控)。
- event.getActionIndex():返回多点触控事件中当前新增触摸点或当前移除触摸点的索引(适用于ACTION_POINTER_DOWN和ACTION_POINTER_UP多点触控相关事件)。
- getPointerId(int index):根据指定索引返回对应触摸点的唯一ID。
- getX(int index)和getY(int index):返回指定索引的触摸点的X和Y坐标。
- getPointerCount():返回当前触摸点的数量。
- findPointerIndex(int pointerId):根据ID查找触摸点当前索引。
触摸点的索引与ID
- 索引:触摸点的编号,从0开始,最大值为getPointerCount()-1。但索引是动态的,会因触摸点的抬起而改变。
- ID:每个触摸点的唯一标识符,在其生命周期内固定不变。因此,ID是跟踪特定触摸点的可靠依据。
例如:一个手指按下,索引为0,ID为0。第二个手指按下,索引为1,ID为1。第一个手指抬起,那么第二个手指的索引变为0,但ID仍为1。
处理多点触控的步骤
1.记录新触摸点
ACTION_DOWN:第一个触摸点按下,记录第一个触摸点的ID和位置(此时ID为0),并添加到Map中。
ACTION_POINTER_DOWN:新增触摸点按下,记录其ID和位置(此时通过getActionIndex()获取新增触摸点的索引,然后将该索引传入getPointerId()中得到对应的触摸点ID;将索引传入getX、getY中得到触摸点位置),并添加到Map中。
2.更新触摸点
ACTION_MOVE:遍历所有触摸点(i in 0..getPointerCount()-1),更新它们的当前位置。
3.移除触摸点
ACTION_POINTER_UP:某个触摸点抬起,获取该触摸点ID(此时通过getActionIndex()获取移除触摸点的索引,然后将该索引传入getPointerId()中得到对应的触摸点ID),在Map中移除。
ACTION_UP:最后一个触摸点抬起,结束整个触摸过程。
实际代码理解
class TouchView(context: Context) : View(context) {
// 使用MutableMap存储触摸点ID和对应的(X, Y)坐标
private val touchPoints = mutableMapOf<Int, Pair<Float, Float>>()
private val paint = Paint().apply {
color = 0xFF0000FF.toInt() // 蓝色
style = Paint.Style.FILL
}
override fun onTouchEvent(event: MotionEvent): Boolean {
when (event.actionMasked) {
MotionEvent.ACTION_DOWN -> {
// 第一个触摸点按下
val id = event.getPointerId(0)
val x = event.getX(0)
val y = event.getY(0)
touchPoints[id] = Pair(x, y)
}
MotionEvent.ACTION_POINTER_DOWN -> {
// 新的触摸点按下
val index = event.actionIndex
val id = event.getPointerId(index)
val x = event.getX(index)
val y = event.getY(index)
touchPoints[id] = Pair(x, y)
}
MotionEvent.ACTION_MOVE -> {
// 触摸点移动,更新所有触摸点位置
for (i in 0 until event.pointerCount) {
val id = event.getPointerId(i)
val x = event.getX(i)
val y = event.getY(i)
touchPoints[id] = Pair(x, y)
}
}
MotionEvent.ACTION_POINTER_UP -> {
// 某个触摸点抬起,移除该触摸点
val index = event.actionIndex
val id = event.getPointerId(index)
touchPoints.remove(id)
}
MotionEvent.ACTION_UP -> {
// 最后一个触摸点抬起,清空Map
touchPoints.clear()
}
MotionEvent.ACTION_CANCEL -> {
// 触摸事件取消,清空Map
touchPoints.clear()
}
}
// 触发重绘
invalidate()
return true
}
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
// 绘制每个触摸点
for ((_, point) in touchPoints) {
canvas.drawCircle(point.first, point.second, 50f, paint)
}
}
}
总结
多点触控的处理是通过 onTouchEvent 方法中的事件(如 ACTION_DOWN、ACTION_POINTER_DOWN、ACTION_MOVE、ACTION_POINTER_UP、ACTION_UP),利用触摸点的唯一 ID 来管理其记录、更新和移除。