Android多点触控最佳实践

作者: mundane | 来源:发表于2017-09-14 11:15 被阅读710次

      好久没有更新自己的简书博客了,说来真是惭愧,感觉自己太点懒了。话说其实坚持写博客还是很有用的,可以梳理自己的知识,帮助自己加深印象,找工作的时候也算是一点筹码,起码能够说明热爱技术并且真的有涉及过,而不是整天在公司混日子,所以今后我应该会增加博客的更新频率。接下来是正题。


    事故现场

      最近在对公司项目中的控件进行优化改造,其中一个是能够上拉和下拉的弹性ScrollView。


      发现没有,当使用一个手指的时候感觉还不错。但是当我想用两个手指交替不断下拉想要把视图内容往下“扒”的时候就办不到了,因为他在onTouchEvent()方法里只是最简单的实现了下拉的逻辑而没有涉及到多指触控,而我想要的效果是像QQ空间或者微信朋友圈那样的。

      注意在第二个手指按下,第一个手指抬起时,此时原本的第二个手指会被识别为第一个,所以图片会直接跳动到第二个手指位置。原因是event.getX()和event.getY中没有传入pointerIndex的参数, 那么默认追踪的就是pointerIndex = 0的手指,当第二个手指按下,第一个手指抬起的时候,触发了move事件,event.getX()和event.getY()此时是获取第二个手指的数据,而lastPoint.x和lastPoint.y并没有在第二个手指按下的时候进行更新,记录的是第一个手指抬起时候的坐标,和evet.getX()、event.getY()有较大的距离, 所以postTranslate了很大一段距离, 发生了跳动的情况。
      为了不出现这种情况,我们可以判断一下 pointId 并且只获取第一个手指的数据,这样就能避免这种情况发生了,如下。
    针对多指触控处理后版本:

    public class DragViewUpGrade extends View {
        String TAG = "DragViewUpGrade";
    
        Bitmap mBitmap;         // 图片
        RectF mBitmapRectF;     // 图片所在区域
        Matrix mBitmapMatrix;   // 控制图片的 matrix
    
        boolean canDrag = false;
        PointF lastPoint = new PointF(0, 0);
    
        public DragViewUpGrade(Context context) {
            this(context, null);
        }
    
        public DragViewUpGrade(Context context, AttributeSet attrs) {
            super(context, attrs);
    
            mDeafultPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
    
            BitmapFactory.Options options = new BitmapFactory.Options();
            options.outWidth = 960/2;
            options.outHeight = 800/2;
    
            mBitmap = BitmapFactory.decodeResource(this.getResources(), R.drawable.poly_test, options);
            mBitmapRectF = new RectF(0,0,mBitmap.getWidth(), mBitmap.getHeight());
            mBitmapMatrix = new Matrix();
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            switch (event.getActionMasked()) {
                case MotionEvent.ACTION_DOWN:
                case MotionEvent.ACTION_POINTER_DOWN:
                    // ▼ 判断是否是第一个手指 && 是否包含在图片区域内
                    if (event.getPointerId(event.getActionIndex()) == 0 && mBitmapRectF.contains((int)event.getX(), (int)event.getY())){
                        canDrag = true;
                        lastPoint.set(event.getX(), event.getY());
                    }
                    break;
                case MotionEvent.ACTION_UP:
                case MotionEvent.ACTION_POINTER_UP:
                    // ▼ 判断是否是第一个手指
                    if (event.getPointerId(event.getActionIndex()) == 0){
                        canDrag = false;
                    }
                    break;
                case MotionEvent.ACTION_MOVE:
                    // 如果存在第一个手指,且这个手指的落点在图片区域内
                    if (canDrag) {
                        // ▼ 注意 getX 和 getY
                        // 只找第一根手指
                        int index = event.findPointerIndex(0);
                        // Log.i(TAG, "index="+index);
                        mBitmapMatrix.postTranslate(event.getX(index)-lastPoint.x, event.getY(index)-lastPoint.y);
                        lastPoint.set(event.getX(index), event.getY(index));
    
                        mBitmapRectF = new RectF(0,0,mBitmap.getWidth(), mBitmap.getHeight());
                        mBitmapMatrix.mapRect(mBitmapRectF);
    
                        invalidate();
                    }
                    break;
            }
    
            return true;
        }
    
        private Paint mDeafultPaint;
    
        @Override
        protected void onDraw(Canvas canvas) {
            canvas.drawBitmap(mBitmap, mBitmapMatrix, mDeafultPaint);
        }
    }
    

    这个也是GcsSloop的代码,因为这里只追踪第一根手指(pointerId = 0的手指),第二根手指的活动全都无视,所以不会再出现跳动的情况



    github地址

    最后是国际惯例,给出demo的github地址MutiTouchDemo

    相关文章

      网友评论

      • 未聞椛洺:没有解决这个问题,当有很多view的时候,界面不能一次显示时,这时不能往上拖动!!!
        mundane:@未聞椛洺 这个我知道,有空会改
      • itlong:楼主的第一个列子是不是有失偏驳,松开第一个手指然后图片跳转到第二个手指根本原因是因为没有监控到第一根手指抬起所致。
        因为action_up只能监控到最后一个手指的抬起
        所以只需要添加对 MotionEvent.ACTION_POINTER_UP 的监控就行了吧(其他的都不需要变)
      • 抹香鲸好吃吗:没有解决嵌套滑动冲突吗? 比如嵌套的是RecyclerView。
        mundane:你说那个弹性的ScrollView吗?这个暂时没考虑, 因为在项目中用的时候只会在里面放一个LinearLayout

      本文标题:Android多点触控最佳实践

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