赞
踩
MotionEvent.getAction() 只能用于单指,考虑多指触控时需要用 MotionEvent.getActionMasked()。常见值:
下面我们会分别看一下这三种类型的多点触控如何使用。
多指触摸时,MotionEvent 会为每个手指分配一个 actionIndex 和 pointerId:
举个例子,第一个手指触摸时,它的 actionIndex 和 pointerId 都为 0,新增第二个手指触摸时,它的 actionIndex 都为 1:
第一个手指 | 第二个手指 | |
---|---|---|
actionIndex | 0 | 1 |
pointerId | 0 | 1 |
此时第一个手指离开屏幕后:
第一个手指(离开) | 第二个手指 | |
---|---|---|
actionIndex | 0 | |
pointerId | 1 |
可以看到,第二个手指的 actionIndex 变成了 0,而 pointerId 没变。
actionIndex 的获取可以直接用 MotionEvent.getActionIndex() 方法获取,而 pointerId 需要用 actionIndex 来获取 :event.getPointerId(actionIndex)。通过 pointerId 也可以获取 actionIndex :findPointerIndex(int pointerId)。
另外,在 View 地 onTouchEvent 方法中,我们平常用 event.getX()、event.getY() 是获取第一个手指的 x 和 y。而如果要获取其他手指,则需要用 getX(int pointerIndex)、getY(int pointerIndex) 获取指定手指的 x、y。
接力型的效果是这样的,比如一个 RecyclerView,第一个手指在上面滑动一段距离后,此时第二个手指也放上来了,那么此时由第二个手指控制滑动,第二个手指松开后,又交由第一个手机控制滑动。简单地说就是同一时刻只有最新地那个手指能起作用地。我们先看一下实现代码:
- class MultiTouchView1(context: Context?, attrs: AttributeSet?) : View(context, attrs) {
-
- companion object {
- val IMAGE_WIDTH = Utils.dp2px(200)
- }
-
- private var mPaint = Paint(Paint.ANTI_ALIAS_FLAG)
- private var mBitmap: Bitmap
-
- //手指按下时的坐标
- private var mDownPoint = PointF()
- //canvas偏移坐标
- private var mCanvasOffsetPoint = PointF()
- //canvas上一次偏移坐标
- private var mCanvasLastOffsetPoint = PointF()
- //当前正在监控的手指
- private var mTrackingPointerId = 0
-
- init {
- mBitmap = Utils.decodeBitmap(resources, R.drawable.avatar, IMAGE_WIDTH.toInt())
- }
-
- @SuppressLint("ClickableViewAccessibility")
- override fun onTouchEvent(event: MotionEvent): Boolean {
- when (event.actionMasked) {
- MotionEvent.ACTION_DOWN, MotionEvent.ACTION_POINTER_DOWN -> {
- setTrackingPointer(event.actionIndex, event)//分析1
- }
- MotionEvent.ACTION_MOVE -> {
- val index = event.findPointerIndex(mTrackingPointerId)
- mCanvasOffsetPoint.x = mCanvasLastOffsetPoint.x + event.getX(index) - mDownPoint.x
- mCanvasOffsetPoint.y = mCanvasLastOffsetPoint.y + event.getY(index) - mDownPoint.y
- invalidate()
- }
- MotionEvent.ACTION_POINTER_UP -> {
- //抬起手指时切换监控的手指
-
- //当前抬起的手指index
- val actionIndex = event.actionIndex
- //当前抬起的手指id
- val pointerId = event.getPointerId(actionIndex)
- //看抬起的手指是否是当前正在监控的手指
- if (pointerId == mTrackingPointerId) {
- //判断抬起的手指是否是最后一个,并将当前追踪点设置为最后一个index对应的point
- val newIndex =
- if (actionIndex == event.pointerCount - 1) event.pointerCount - 2 else event.pointerCount - 1//分析2
- setTrackingPointer(newIndex, event)
- }
- }
- }
- return true
- }
-
- /**
- * 设置当前追踪的 Pointer
- */
- private fun setTrackingPointer(newPointIndex: Int, event: MotionEvent) {
- mTrackingPointerId = event.getPointerId(newPointIndex)
- mDownPoint.x = event.getX(newPointIndex)
- mDownPoint.y = event.getY(newPointIndex)
- mCanvasLastOffsetPoint.x = mCanvasOffsetPoint.x
- mCanvasLastOffsetPoint.y = mCanvasOffsetPoint.y//分析3
- }
-
- override fun onDraw(canvas: Canvas) {
- canvas.drawBitmap(mBitmap, mCanvasOffsetPoint.x, mCanvasOffsetPoint.y, mPaint)
- }
- }

接下来我们来分析一下:
假如当前抬起的手指是最后一个按下的手指(即index为4的手指),那么抬起后应切换当前监控的 index 为 pointerCount - 2 (即index为3的手指) 。如果不是最后一个按下的手指(假如是index为3的手指),那么抬起后应切换当前监控的 index 为 pointerCount - 1(即 index 为4的手指)。
配合型 / 协作型即所有触摸到 View 的 pointer 共同起作用,比如可以多指滑动列表,滑动的距离即多指的焦点(中点)
- /**
- * 多指触控:协作型
- * 忽略个体,只看整体的焦点
- */
- class MultiTouchView2(context: Context?, attrs: AttributeSet?) : View(context, attrs) {
-
- companion object {
- val IMAGE_WIDTH = Utils.dp2px(200)
- }
-
- private var mPaint = Paint(Paint.ANTI_ALIAS_FLAG)
- private var mBitmap: Bitmap
-
- //手指按下时的坐标
- private var mDownPoint = PointF()
- //canvas偏移坐标
- private var mCanvasOffsetPoint = PointF()
- //canvas上一次偏移坐标
- private var mCanvasLastOffsetPoint = PointF()
- //所有pointer的焦点(中心点)
- private var mPointerFocusPoint = PointF()
- //pointer数量
- private var mPointerCount = 0
-
- init {
- mBitmap = Utils.decodeBitmap(resources, R.drawable.avatar, IMAGE_WIDTH.toInt())
- }
-
- @SuppressLint("ClickableViewAccessibility")
- override fun onTouchEvent(event: MotionEvent): Boolean {
- //pointer数量
- mPointerCount = event.pointerCount
- //所有pointer的x、y总和
- var sumX = 0f
- var sumY = 0f
- //是否是pointer_up事件
- val isPointerUp = event.actionMasked == MotionEvent.ACTION_POINTER_UP
-
- for (i in 0 until mPointerCount) {
- //抬起的那个pointer不用计算
- if (!(isPointerUp && i == event.actionIndex)) {
- sumX += event.getX(i)
- sumY += event.getY(i)
- }
- }
-
- if (isPointerUp) {
- //如果是pointer_up抬起事件,则pointer总数量-1
- mPointerCount -= 1
- }
- //计算焦点
- mPointerFocusPoint.x = sumX / mPointerCount
- mPointerFocusPoint.y = sumY / mPointerCount
-
- when (event.actionMasked) {
- MotionEvent.ACTION_DOWN,
- MotionEvent.ACTION_POINTER_DOWN,
- MotionEvent.ACTION_POINTER_UP -> {
- mDownPoint.x = mPointerFocusPoint.x
- mDownPoint.y = mPointerFocusPoint.y
- mCanvasLastOffsetPoint.x = mCanvasOffsetPoint.x
- mCanvasLastOffsetPoint.y = mCanvasOffsetPoint.y
- }
- MotionEvent.ACTION_MOVE -> {
- mCanvasOffsetPoint.x = mCanvasLastOffsetPoint.x + mPointerFocusPoint.x - mDownPoint.x
- mCanvasOffsetPoint.y = mCanvasLastOffsetPoint.y + mPointerFocusPoint.y - mDownPoint.y
- invalidate()
- }
- }
- return true
- }
-
- override fun onDraw(canvas: Canvas) {
- canvas.drawBitmap(mBitmap, mCanvasOffsetPoint.x, mCanvasOffsetPoint.y, mPaint)
- }
- }

主要的应用场景是绘图应用,多个手指可以同时个不干扰的绘制,实现也较简单,我们直接看下代码就能明白:
- /**
- * 多指触控:各自为战型
- */
- class MultiTouchView3(context: Context?, attrs: AttributeSet?) : View(context, attrs) {
-
- private var mPaint = Paint(Paint.ANTI_ALIAS_FLAG)
- private var mPaths = SparseArray<Path>()
-
- init {
- mPaint.style = Paint.Style.STROKE
- mPaint.strokeWidth = Utils.dp2px(4)
- mPaint.strokeCap = Paint.Cap.ROUND
- mPaint.strokeJoin = Paint.Join.ROUND
- }
-
- @SuppressLint("ClickableViewAccessibility")
- override fun onTouchEvent(event: MotionEvent): Boolean {
-
- when (event.actionMasked) {
- MotionEvent.ACTION_DOWN,
- MotionEvent.ACTION_POINTER_DOWN -> {
- val actionIndex = event.actionIndex
- val pointerId = event.getPointerId(actionIndex)
- val path = Path()
- path.moveTo(event.getX(actionIndex), event.getY(actionIndex))
- mPaths.append(pointerId, path)
- }
- MotionEvent.ACTION_MOVE -> {
- for (i in 0 until event.pointerCount) {
- val path = mPaths.get(event.getPointerId(i))
- path.lineTo(event.getX(i), event.getY(i))
- }
- invalidate()
- }
- MotionEvent.ACTION_UP,
- MotionEvent.ACTION_POINTER_UP -> {
- //抬起手指时删除绘制
- val pointerId = event.getPointerId(event.actionIndex)
- mPaths.remove(pointerId)
- invalidate()
- }
- }
- return true
- }
-
- override fun onDraw(canvas: Canvas) {
- for (i in 0 until mPaths.size()) {
- canvas.drawPath(mPaths.valueAt(i), mPaint)
- }
- }
- }

Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。