真的很简单的多点触控

2021-04-24  本文已影响0人  王灵

对触摸事件有基础了解的情况下,如果能准确的获取自己的每个手指的相关数据,应该就能很好的多点触控在各种情况下的行为了

一、actionMasked

我们一般重写onTouchEvent函数时都会通过event.action来获取事件的类型。但是在处理多点触控的时候我们需要使用event.actionMasked,因为event.action它不支持多点

二、获取触摸点的数据

所谓触摸点的数据,我们需要的不就是它x,y坐标呗!
在没有学习多点触摸的时候我们获取点的坐标都是通过event.getX()event.getY()。看看它的内部实现

    /**
     * {@link #getX(int)} for the first pointer index (may be an
     * arbitrary pointer identifier).
     *
     * @see #AXIS_X
     */
    public final float getX() {
        return nativeGetAxisValue(mNativePtr, AXIS_X, 0, HISTORY_CURRENT);
    }

实际上它等价于event.getX(0)

    public final float getX(int pointerIndex) {
        return nativeGetAxisValue(mNativePtr, AXIS_X, pointerIndex, HISTORY_CURRENT);
    }

不错,其实getXgetY是可以填参数的。pointerIndex

看到这里我想大家都明白了,实际上触摸事件的数据是存在列表里的。通过下标去获取对于的数据。而在实际的多点事件中手指的index会随着手指的按下和抬起而发生变化,并不能将数据与手指形成绑定关系;要想一直获取到对应手指的数据我们需要另寻他法

按下和抬起事件与MotionEvent.ACTION_MOVE有一个特别特征,唯一性。按下和抬起事件中必定有一个手指按下或者抬起。而我们可以通过event.actionIndex获取到它在事件列表中对应的下标。

override fun onTouchEvent(event: MotionEvent): Boolean {
        when (event.actionMasked) {
            MotionEvent.ACTION_DOWN, MotionEvent.ACTION_POINTER_DOWN -> {
                val actionIndex = event.actionIndex
            }
            MotionEvent.ACTION_MOVE -> {

            }
            MotionEvent.ACTION_UP, MotionEvent.ACTION_POINTER_UP -> {
                 val actionIndex=event.actionIndex
            }
        }
        return true
    }

event.getPointerId函数在多点触控可谓是至关重要,因为它可以根据下标获取到手指的id。没错这个id在按下是生成,在抬起时销毁,伴随一个完整的事件流程。id与手指的事件存在绑定的关系

三、多指画图示例

多指画图.gif

图很丑。。。
实现的示例很简单,用path把手指的移动轨迹保存下来,然后绘制

class MultiTouchView3(context: Context?, attrs: AttributeSet?) : View(context, attrs) {

    private val paint = Paint(Paint.ANTI_ALIAS_FLAG)
    private val paths = SparseArray<Path>()//多指操作,肯定需要保存多条path


    init {
        paint.style = Paint.Style.STROKE
        paint.strokeWidth = 4.dp
        paint.strokeCap = Paint.Cap.ROUND
        paint.strokeJoin = Paint.Join.ROUND
    }
   //把path遍历出来进行绘制就可以了
    override fun onDraw(canvas: Canvas) {
        for (i in 0 until paths.size()) {
            canvas.drawPath(paths.valueAt(i), paint)
        }
    }
    override fun onTouchEvent(event: MotionEvent): Boolean {

    }

需要注意的是paths.valueAt函数,我们通过下标去获取对应的path。而不是使用paths.get(),以为get的参数是key并不是下标。key就是我们的id,唯一的

    /**
     * Gets the Object mapped from the specified key, or <code>null</code>
     * if no such mapping has been made.
     */
    public E get(int key) {
        return get(key, null);
    }

如何生成path并添加数据

            MotionEvent.ACTION_DOWN, MotionEvent.ACTION_POINTER_DOWN -> {
                //添加新的路径 key是id
                val actionIndex = event.actionIndex
                val id = event.getPointerId(actionIndex)
                val path = Path()
                path.moveTo(event.getX(actionIndex), event.getY(actionIndex))
                paths.append(id, path)
            }
            MotionEvent.ACTION_UP, MotionEvent.ACTION_POINTER_UP -> {
                //删除路径,key是id
                paths.remove(event.getPointerId(event.actionIndex))
                invalidate()
            }
            MotionEvent.ACTION_MOVE -> {
                //根据id去添加路径
                for (i in 0 until event.pointerCount) {
                    val pointerId = event.getPointerId(i)
                    paths[pointerId].lineTo(event.getX(i), event.getY(i))
                }
                invalidate()
            }

完整的代码

class MultiTouchView3(context: Context?, attrs: AttributeSet?) : View(context, attrs) {

    private val paint = Paint(Paint.ANTI_ALIAS_FLAG)
    private val paths = SparseArray<Path>()


    init {
        paint.style = Paint.Style.STROKE
        paint.strokeWidth = 4.dp
        paint.strokeCap = Paint.Cap.ROUND
        paint.strokeJoin = Paint.Join.ROUND
    }

    override fun onDraw(canvas: Canvas) {
        for (i in 0 until paths.size()) {
            canvas.drawPath(paths.valueAt(i), paint)
        }
    }

    override fun onTouchEvent(event: MotionEvent): Boolean {
        when (event.actionMasked) {
            MotionEvent.ACTION_DOWN, MotionEvent.ACTION_POINTER_DOWN -> {
                //添加新的路径 key是id
                val actionIndex = event.actionIndex
                val id = event.getPointerId(actionIndex)
                val path = Path()
                path.moveTo(event.getX(actionIndex), event.getY(actionIndex))
                paths.append(id, path)
            }
            MotionEvent.ACTION_MOVE -> {
                //根据id去添加路径
                for (i in 0 until event.pointerCount) {
                    val pointerId = event.getPointerId(i)
                    paths[pointerId].lineTo(event.getX(i), event.getY(i))
                }
                invalidate()
            }
            MotionEvent.ACTION_UP, MotionEvent.ACTION_POINTER_UP -> {
                //删除路径,key是id
                paths.remove(event.getPointerId(event.actionIndex))
                invalidate()
            }
        }
        return true
    }
}
上一篇下一篇

猜你喜欢

热点阅读