GcsSloop / AndroidNote

安卓学习笔记
http://www.gcssloop.com/#blog
9.17k stars 2.14k forks source link

不规则图形的点击事件以及画布变换后触摸操作处理 #41

Open 516457377 opened 8 years ago

516457377 commented 8 years ago

比如我画了这样两个圆, canvas.drawCircle(20, 20, 10, mPaint); canvas.drawCircle(40, 40, 10, mPaint); 我想要点击两个圆都有不同的是事件触发该如何实现。求教~谢谢

GcsSloop commented 8 years ago

以下方法可以用于任何不规则图形的点击事件判断。

创建一个全局的Region(区域)

通过setPath方法为Region设置区域,

onTouchEvent中使用Region的contains判断是否在区域内

在onDraw里面绘制path

public class RegionClickView extends View {
    Paint mPaint;
    Region globalRegion;
    Region circleRegion1;
    Region circleRegion2;
    Path circlePath1;
    Path circlePath2;

    public RegionClickView(Context context) {
        super(context);

        mPaint = new Paint();
        mPaint.setStyle(Paint.Style.FILL);
        mPaint.setColor(Color.GRAY);

        circlePath1 = new Path();
        circlePath2 = new Path();

        circleRegion1 = new Region();
        circleRegion2 = new Region();

        circlePath1.addCircle(100, 100, 50, Path.Direction.CW);
        circlePath2.addCircle(400, 400, 50, Path.Direction.CW);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        globalRegion = new Region(0, 0, w, h);
        circleRegion1.setPath(circlePath1, globalRegion);
        circleRegion2.setPath(circlePath2, globalRegion);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN:
                int x = (int) event.getX();
                int y = (int) event.getY();

                // 点击区域判断
                if (circleRegion1.contains(x,y)){
                    Toast.makeText(this.getContext(),"圆1被点击",Toast.LENGTH_SHORT).show();
                }
                if (circleRegion2.contains(x,y)){
                    Toast.makeText(this.getContext(),"圆2被点击",Toast.LENGTH_SHORT).show();
                }

                break;
        }

        return super.onTouchEvent(event);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        canvas.drawPath(circlePath1,mPaint);
        canvas.drawPath(circlePath2,mPaint);
    }
}
516457377 commented 8 years ago

大牛,感谢~~~

zzjian commented 8 years ago

请问一下,如果我将画布平移或缩放了(例如 canvas.translate(100, 100)),在onTouchEvent中可以直接获取相对于改变后画布的x、y坐标么

GcsSloop commented 8 years ago

一个简单的事例,在画布平移和缩放的情况下,如何在手指按下位置绘制一个小圆。

public class TouchPointTest extends CustomView {
    float[] pts = new float[2];             // 存储手指按下位置

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

    public TouchPointTest(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN:
                pts[0] = event.getRawX();   // 注意,要获取全局的坐标 RawX 和 RawY
                pts[1] = event.getRawY();
                invalidate();               // 刷新界面
                break;
        }
        return super.onTouchEvent(event);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        canvas.translate(mViewWidth/2, mViewHeight/2);  // 平移
        canvas.scale(0.5f, 0.5f);                       // 缩放

        // 获得当前矩阵的逆矩阵
        Matrix invertMatrix = new Matrix();
        canvas.getMatrix().invert(invertMatrix);

        // 使用 mapPoints 将触摸位置转换为画布坐标
        invertMatrix.mapPoints(pts);

        // 在这个位置绘制一个小圆
        canvas.drawCircle(pts[0],pts[1],50,mDeafultPaint);
    }
}