Android自定义View中的缩放及拖拽事件处理

2019-06-29 / 5 阅读 / Android

自定义View中处理简单的拖拽及缩放事件。

因为经常需要使用到,所以花时间整理了简单的用法,及给出Demo。以后再用到方面直接上手。

其中往边界拖拽时会有回弹的效果

 

其中用到了组件
1、Scroller 用于View能够平滑滚动,配合重写computeScroll()完成
2、ScaleGestureDetector 缩放手势类,捕捉双手指放大缩小事件
3、GestureDetector 普通手势类,处理移动,点击,双击等事件,示例中只使用了拖动事件
4、Matrix 矩阵,配合Canvas能够对View放大缩小,平移等变形

package xyz.wbsite.wbui;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;
import android.widget.Scroller;

public class MyView extends View implements View.OnTouchListener {
    private Scroller scroller = new Scroller(getContext());
    private ScaleGestureDetector scaleGestureDetector;
    private GestureDetector gestureDetector;
    private Matrix matrix;
    private Paint paint;
    private float scale = 1.0f;
    private int dX = 0;
    private int dY = 0;

    private int width = 500;
    private int height = 500;

    public MyView(Context context) {
        super(context);
    }

    public MyView(Context context, AttributeSet attrs) {
        super(context, attrs);
        //初始化
        matrix = new Matrix();
        scaleGestureDetector = new ScaleGestureDetector(getContext(), new ScaleGestureDetector.OnScaleGestureListener() {
            @Override
            public boolean onScale(ScaleGestureDetector detector) {
                //记录缩放参数,留在onDraw中处理变形
                scale = scale * detector.getScaleFactor();
                invalidate();
                return true;
            }

            @Override
            public boolean onScaleBegin(ScaleGestureDetector detector) {
                return true;
            }

            @Override
            public void onScaleEnd(ScaleGestureDetector detector) {
                invalidate();
            }
        });

        gestureDetector = new GestureDetector(getContext(), new GestureDetector.SimpleOnGestureListener() {
            @Override
            public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
                //记录平移参数,留在onDraw中处理变形
                dX += -distanceX;
                dY += -distanceY;
                System.out.println("distanceX" + -distanceX + "," + dX);
                invalidate();
                return true;
            }
        });
        paint = new Paint();
        paint.setColor(Color.RED);
        this.setOnTouchListener(this);
    }

    @Override
    public boolean performClick() {
        return super.performClick();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        //组合缩放及平移参数,其中set、pre、post区别可以自行查找资料
        matrix.setScale(scale, scale);
        matrix.postTranslate(dX, dY);
        canvas.concat(matrix);
        //这边绘制自己的图形
        canvas.drawRect(0, 0, width, height, paint);
    }

    @Override
    public void computeScroll() {
        super.computeScroll();
        if (scroller.computeScrollOffset()) {
            dX = scroller.getCurrX();
            dY = scroller.getCurrY();

            System.out.println("computeScroll=" + dX);
            postInvalidate();
        }
    }

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN: {
                if (!scroller.isFinished()) {
                    scroller.abortAnimation();
                }
            }
            break;
            case MotionEvent.ACTION_UP: {//抬起时,计算回弹,以左上角的点为准,在一个矩形中,如果不在则回弹到这个矩形的边界。保证视图可见。
                int minX = (int) (getMeasuredWidth() < scale * width ? getMeasuredWidth() - scale * width : 0);
                int minY = (int) (getMeasuredHeight() < scale * height ? getMeasuredHeight() - scale * height : 0);
                int maxX = (int) (getMeasuredWidth() < scale * width ? 0 : getMeasuredWidth() - scale * width);
                int maxY = (int) (getMeasuredHeight() < scale * height ? 0 : getMeasuredHeight() - scale * height);
                Rect rect = new Rect(minX, minY, maxX, maxY);

                if (!rect.contains(dX, dY)) {
                    int dx = 0;
                    int dy = 0;

                    if (dX < minX) {
                        dx = minX - dX;
                    } else if (dX > maxX) {
                        dx = maxX - dX;
                    }

                    if (dY < minY) {
                        dy = minY - dY;
                    } else if (dY > maxY) {
                        dy = maxY - dY;
                    }

                    System.out.println("dX=" + dX + ",dY=" + dY + ";dx=" + dx + ",dy=" + dy);
                    scroller.startScroll(dX, dY, dx, dy);
                    postInvalidate();
                }
            }
            break;
        }
        scaleGestureDetector.onTouchEvent(event);
        gestureDetector.onTouchEvent(event);
        return true;
    }
}
相关推荐