美文网首页
真的很简单的多点触控

真的很简单的多点触控

作者: 王灵 | 来源:发表于2021-04-24 17:37 被阅读0次

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

    一、actionMasked

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

    二、获取触摸点的数据

    • event.getX() event.getY()

    所谓触摸点的数据,我们需要的不就是它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会随着手指的按下和抬起而发生变化,并不能将数据与手指形成绑定关系;要想一直获取到对应手指的数据我们需要另寻他法

    • event.actionIndex

    按下和抬起事件与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

    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并添加数据

    • 在按下事件新建path并添加到paths
                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)
                }
    
    • 在抬起事件中去删除path
                MotionEvent.ACTION_UP, MotionEvent.ACTION_POINTER_UP -> {
                    //删除路径,key是id
                    paths.remove(event.getPointerId(event.actionIndex))
                    invalidate()
                }
    
    • 在MOVE事件中去根据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()
                }
    

    完整的代码

    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
        }
    }
    

    相关文章

      网友评论

          本文标题:真的很简单的多点触控

          本文链接:https://www.haomeiwen.com/subject/ugrlrltx.html