在Android画布上应用缩放效果后,缩放比例位置错误

首先这是一个跟随问题,原来在这里提出,Pan,Zoom and Scale a custom View for Canvas drawing in Android

既然没有答案,我终于用android-gesture-detectors解决了我的问题

应用缩放/缩放手势后,我发现画布绘图坐标仍然指向旧位置(在应用缩放之前),而不是绘制完全相同的触摸坐标.基本上,在缩放或拖动画布后,无法获得正确的画布坐标.

放大前,

缩小之后,触摸点正在绘制上一个位置.我想让它画在当前的触摸位置,

示例代码,

public class DrawingView extends View {

    private void setupDrawing() {

        mScaleDetector = new ScaleGestureDetector(getContext(),new ScaleListener());

        mgd = new MoveGestureDetector(ctx,mgl);
        sgd = new ScaleGestureDetector(ctx,sgl);
        rgd = new RotateGestureDetector(ctx,rgl);

}

class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
        @Override
        public boolean onScale(ScaleGestureDetector detector) {
            mScaleFactor *= detector.getScaleFactor();
            // Don't let the object get too small or too large.
            mScaleFactor = Math.max(0.1f,Math.min(mScaleFactor,5.0f));
            invalidate();
            return true;
        }
    }

    MoveGestureDetector.SimpleOnMoveGestureListener mgl = new MoveGestureDetector.SimpleOnMoveGestureListener() {
        @Override
        public boolean onMove(MoveGestureDetector detector) {
            PointF delta = detector.getFocusDelta();
            matrix.postTranslate(delta.x,delta.y);
            invalidate();
            return true;
        }
    };

    ScaleGestureDetector.SimpleOnScaleGestureListener sgl = new ScaleGestureDetector.SimpleOnScaleGestureListener() {
        @Override
        public boolean onScale(ScaleGestureDetector detector) {
            float scale = detector.getScaleFactor();
            matrix.postScale(scale,scale,detector.getFocusX(),detector.getFocusY());
            invalidate();
            return true;
        }
    };

    RotateGestureDetector.SimpleOnRotateGestureListener rgl = new RotateGestureDetector.SimpleOnRotateGestureListener() {
        @Override
        public boolean onRotate(RotateGestureDetector detector) {
            matrix.postRotate(-detector.getRotationdegreesDelta(),detector.getFocusY());
            invalidate();
            return true;
        }
    };

    @Override
    protected void onSizeChanged(int w,int h,int oldw,int oldh) {
        //view given size
        super.onSizeChanged(w,h,oldw,oldh);
        canvasBitmap = Bitmap.createBitmap(w,Bitmap.Config.ARGB_8888);
        drawCanvas = new Canvas(canvasBitmap);
    }

    private void touch_start(float x,float y) {
        undonePaths.clear();
        drawPath.reset();
        drawPath.moveto(x,y);
        mX = x;
        mY = y;
    }

    private void touch_move(float x,float y,float x2,float y2) {
        float dx = Math.abs(x - mX);
        float dy = Math.abs(y - mY);
        if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
           /* QUad to curves using a quadratic line (basically an ellipse of some sort).
           Lineto is a straight line. QuadTo will smooth out jaggedies where they turn.
          */
            drawPath.quadTo(mX,mY,(x + mX) / 2,(y + mY) / 2);
            mX = x;
            mY = y;
        }

    }

    private void touch_up() {

            drawPath.lineto(mX,mY);
            // commit the path to our offscreen
            drawCanvas.drawPath(drawPath,drawPaint);
            // kill this so we don't double draw
            paths.add(drawPath);
            drawPath = new Path();
            drawPath.reset();
            invalidate();
    }

@Override
    public boolean onTouchEvent(MotionEvent event) {

        if (isZoomable) {
            mgd.onTouchEvent(event);
            sgd.onTouchEvent(event);
            rgd.onTouchEvent(event);
        }

        if (!isTouchable) {
            return super.onTouchEvent(event);
        } else {
            //detect user touch
            float x = event.getX();
            float y = event.getY();

            switch (event.getAction() & MotionEvent.ACTION_MASK) {

                case MotionEvent.ACTION_DOWN:
                    if (!isZoomable) {
                        touch_start(x,y);
                    }
                    invalidate();
                    break;

                case MotionEvent.ACTION_MOVE:
                    if (!isZoomable) {
                        //mPositions.add(new Vector2(x - mBitmapBrushDimensions.x / 2,y - mBitmapBrushDimensions.y / 2));
                        if (isCustomBrush && mBitmapBrushDimensions != null) {
                            mPositions = new Vector2(x - mBitmapBrushDimensions.x / 2,y - mBitmapBrushDimensions.y / 2);
                            touch_move(x,y,x - mBitmapBrushDimensions.x / 2,y - mBitmapBrushDimensions.y / 2);
                        } else {
                            touch_move(x,0);
                        }
                    }
                    invalidate();
                    break;

                case MotionEvent.ACTION_UP:
                    if (!isZoomable) {
                        touch_up();
                    }
                    invalidate();
                    break;
            }
            mScaleDetector.onTouchEvent(event);
            return true;
        }
    }

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

        canvas.setMatrix(matrix);

        for (Path p : paths) {
                canvas.drawPath(p,drawPaint);
                drawPaint.setColor(selectedColor);
                drawPaint.setstrokeWidth(brushSize);
                canvas.drawPath(drawPath,drawPaint);
        }
        canvas.restore();
    }
}

PS:MoveGestureDetector(),ScaleGestureDetector()& RotateGestureDetector()是从android-gesture-detectors继承的自定义

解决方法

这是我做的基本上你必须找到“旧”和新点之间的区别.跳到底部的重要线条…
@Override
public boolean onScale(ScaleGestureDetector detector) {

    scaleFactor *= detector.getScaleFactor();

    float xDiff = initialFocalPoints[0] - currentFocalPoints[0];
    float yDiff = initialFocalPoints[1] - currentFocalPoints[1];

    transformMatrix.setScale(scaleFactor,scaleFactor,currentFocalPoints[0],currentFocalPoints[1]);
    transformMatrix.postTranslate(xDiff,yDiff);    
    child.setimageMatrix(transformMatrix);

    return true;
}

@Override
public boolean onScaleBegin(ScaleGestureDetector detector){

    float startX = detector.getFocusX() + getScrollX();
    float startY = detector.getFocusY() + getScrollY();

    initialFocalPoints = new float[]{startX,startY};

    if(transformMatrix.invert(inverseTransformMatrix))
    inverseTransformMatrix.mapPoints(currentFocalPoints,initialFocalPoints);
    return true;
}

有所区别的线条如下:

float xDiff = initialFocalPoints[0] - currentFocalPoints[0];
float yDiff = initialFocalPoints[1] - currentFocalPoints[1];
transformMatrix.postTranslate(xDiff,yDiff);

答案很简单,就是找出两点之间的区别,并且每次图像缩放时都可以翻译图像视图.

相关文章

Android性能优化——之控件的优化 前面讲了图像的优化,接下...
前言 上一篇已经讲了如何实现textView中粗字体效果,里面主要...
最近项目重构,涉及到了数据库和文件下载,发现GreenDao这个...
WebView加载页面的两种方式 一、加载网络页面 加载网络页面,...
给APP全局设置字体主要分为两个方面来介绍 一、给原生界面设...
前言 最近UI大牛出了一版新的效果图,按照IOS的效果做的,页...