首页 > 解决方案 > 缩放时画布不在手指位置上绘制

问题描述

我正在尝试制作一个绘画应用程序。缩放有点工作,当我尝试在缩放后在画布上绘制时,它不会在手指的位置上绘制。相反,它会在设备屏幕上绘制比例。

我做了一些研究,但找不到解决方案的答案。-> 浮点 x = (event.getX() - scalePointX)/mScaleFactor;// 不起作用,

我试图实现矩阵但没有成功。当画布放大或缩小时,有人可以帮我在手指上画画吗?

谢谢!

public class paintView extends View {

    Paint paint;
    Path path;
    Bitmap bitmap;
    Canvas mcanvas;
    private final float TOUCH_TOLERANCE = 4;
    private float mX, mY;
    public static final int DEFAULT_BG_COLOR = Color.WHITE;
    private int backgroundColor = DEFAULT_BG_COLOR;
    private ArrayList<FingerPath> paths = new ArrayList<>();
    private Paint mBitmapPaint = new Paint(Paint.DITHER_FLAG);

    private final ScaleGestureDetector mScaleGesture;
    private float mScaleFactor = 1.f;
    private float mPosX;
    private float mPosY;
    private  float scalePointX, scalePointY;


    private Rect clipBounds_canvas;

    public paintView(Context context) {
        this(context, null);
    }

    public paintView(Context context, AttributeSet attrs){
        super(context, attrs);

        mScaleGesture = new ScaleGestureDetector(context, new ScaleListener());

        paint = new Paint();
        paint.setAntiAlias(true);
        paint.setColor(Color.BLACK);
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeWidth(8f);

    }

    public void init(DisplayMetrics metrics){
        int height = metrics.heightPixels;
        int width = metrics.widthPixels;

        bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        mcanvas = new Canvas(bitmap);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        canvas.save();
        mcanvas.drawColor(backgroundColor);

        clipBounds_canvas = canvas.getClipBounds();

        for(FingerPath fp: paths){
            paint.setMaskFilter(null);

            mcanvas.drawPath(fp.path, paint);
        }
        canvas.translate(mPosX, mPosY);
        canvas.scale(mScaleFactor, mScaleFactor,scalePointX,scalePointY);

        canvas.drawBitmap(bitmap, 0, 0, mBitmapPaint);
        canvas.restore();

    }

    private void touchStart(float x, float y){
        path = new Path();
        FingerPath fp = new FingerPath(path);
        paths.add(fp);

        path.reset();
        path.moveTo(x,y);

        mX = x;
        mY = y;
    }

    private void touchMove(float x, float y){
        float dx = Math.abs(x - mX);
        float dy = Math.abs(y - mY);

        if(dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE ){
            path.quadTo(mX, mY, (x+mX)/2, (y+mY)/2);
            mX = x;
            mY = y;
        }
    }

    private void touchUp(){
        path.lineTo(mX,mY);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        final float x = (event.getX() - scalePointX)/mScaleFactor;
        final float y = (event.getY() - scalePointY)/mScaleFactor;

        mScaleGesture.onTouchEvent(event);
        final int action = event.getAction();

        switch(action & MotionEvent.ACTION_MASK){
            case MotionEvent.ACTION_DOWN:
                touchStart(x, y);
                invalidate();
                break;
            case MotionEvent.ACTION_MOVE:
                touchMove(x,y);
                invalidate();
                break;
            case MotionEvent.ACTION_UP:
                touchUp();
                invalidate();
                break;
        }
        return true;
    }

    public class FingerPath {

        public Path path;

        public FingerPath(Path path) {
            this.path = path;
        }
    }
    private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {

        @Override
        public boolean onScale(ScaleGestureDetector detector) {
            mScaleFactor *= detector.getScaleFactor();
            scalePointX = detector.getFocusX();
            scalePointY = detector.getFocusY();
            // Don't let the object get too small or too large.
            mScaleFactor = Math.max(0.5f, Math.min(mScaleFactor, 3.0f));

            //zoom out 'up to' the size of canvas(screen size)
            //mScaleFactor = (mScaleFactor < 1 ? 1 : mScaleFactor);

            invalidate();
            return true;
        }

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

    }
}

标签: javaandroidandroid-studio

解决方案


我遇到了这个问题,并且能够用This stack overflow question解决它。我所做的是存储当前的比例偏移量,当我绘制新路径时,我将绘制矩阵偏移这个存储的值。您的解决方案非常接近,您可以缩放绘图矩阵,而不是缩放画布。还有一个友好的提示,您可能还需要在缩放后缩放线条粗细,因此请使用与缩放相同的值。


推荐阅读