安卓基础知识Android开发经验谈Android技术知识

Android多点触控最佳实践

2017-09-14  本文已影响710人  mundane

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


事故现场

  最近在对公司项目中的控件进行优化改造,其中一个是能够上拉和下拉的弹性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

上一篇 下一篇

猜你喜欢

热点阅读