捏缩放(绘图线)Android Canvas后获取正确的坐标

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了捏缩放(绘图线)Android Canvas后获取正确的坐标相关的知识,希望对你有一定的参考价值。

我正在尝试用用户的手指(触摸)画一条线。如果没有缩放比例,则实现起来非常容易。没有缩放的绘图效果很好,这里是屏幕截图

enter image description here

效果很好。如你看到的。

但是如果我缩放画布,它将开始以一些边距/测量误差/公差绘制点。似乎我在计算缩放的接触点时没有预先取值,我尝试了很多不同的公式,但是没有任何帮助。

这里是缩放画布的结果。enter image description here

似乎我必须考虑到某些增量值中的问题

因为如果使用此版本的缩放功能,它可以很好地工作,但只能缩放到左上角。

canvas.scale(mScaleFactor, mScaleFactor); 

具有此缩放比例

canvas.scale(mScaleFactor, mScaleFactor, scalePointX, scalePointY);

多点触控缩放(捏)效果很好,但坐标不正确。

[请帮助解决问题,似乎在计算缩放的x和y时我必须采用这些scalePointX, scalePointY变量。

这是我的代码。任何帮助将不胜感激。

private void initWorkSpace(Context context) 
        mPaint = new Paint();
        mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
        mRect = new Rect();
        mPath = new Path();
        mPaint.setAntiAlias(true);
        mPaint.setColor(Color.BLACK);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeJoin(Paint.Join.ROUND);
        mPaint.setStrokeWidth(10f);
    
    @Override
    protected void onDraw(Canvas canvas) 
        super.onDraw(canvas);
        canvas.getClipBounds(mRect);
        canvas.save();
        canvas.scale(mScaleFactor, mScaleFactor, scalePointX, scalePointY);
        canvas.translate(mRect.top,mRect.left);
        canvas.drawPath(mPath, mPaint);
        canvas.restore();

    
    // when ACTION_DOWN start touch according to the x,y values
    private void startTouch(float x, float y) 
        mPath.moveTo(x, y);
        mX = x;
        mY = y;
    

    // when ACTION_MOVE move touch according to the x,y values
    private void moveTouch(float x, float y) 
        float dx = Math.abs(x - mX);
        float dy = Math.abs(y - mY);
        if (dx >= TOLERANCE || dy >= TOLERANCE) 
            mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
            mX = x;
            mY = y;
        
    

    public void clearCanvas() 
        mPath.reset();
        invalidate();
    

    // when ACTION_UP stop touch
    private void upTouch() 
        mPath.lineTo(mX, mY);
    

    @Override
    public boolean onTouchEvent(MotionEvent ev) 
        // Let the ScaleGestureDetector inspect all events.
        mScaleDetector.onTouchEvent(ev);

        final int action = ev.getAction();
        Log.e("TOUCH","REAL X :" + ev.getX() + " REAL Y : " + ev.getY());
        Log.e("TOUCH","RECT TOP :" + mRect.top + " RECT LEFT : " + mRect.left + " RECT RIGHT : " + mRect.right + " RECT BOTTOM :" + mRect.bottom);
        final float scaledX = ev.getX()/mScaleFactor+mRect.left*mScaleFactor;
        final float scaledY = ev.getY()/mScaleFactor+mRect.top*mScaleFactor;
        switch (action & MotionEvent.ACTION_MASK) 
            case MotionEvent.ACTION_DOWN: 

                /*final float x = (ev.getX() - scalePointX) / mScaleFactor;
                final float y = (ev.getY() - scalePointY) / mScaleFactor;
                cX = x - mPosX + scalePointX; // canvas X
                cY = y - mPosY + scalePointY; // canvas Y*/

                // Remember where we started
                mLastTouchX = scaledX;
                mLastTouchY = scaledY;
                Log.e("DOWN","Scale FACTOR : " + mScaleFactor);
                Log.e("DOWN","X : " +mLastTouchX + " Y :" + mLastTouchY + " scalePointX : " + scalePointX + " scalePointY : " + scalePointY );

                Log.e("DOWN","Last X : " + mLastTouchY + " Last Y :" + mLastTouchY);
                startTouch(mLastTouchX, mLastTouchY);
                invalidate();
                break;
            
            case MotionEvent.ACTION_MOVE: 
               /* final float x = (ev.getX() - scalePointX) / mScaleFactor;
                final float y = (ev.getY() - scalePointY) / mScaleFactor;
                cX = x - mPosX + scalePointX; // canvas X
                cY = y - mPosY + scalePointY; // canvas Y

                // Only move if the ScaleGestureDetector isn't processing a gesture.
                if (!mScaleDetector.isInProgress()) 
                    final float dx = x - mLastTouchX; // change in X
                    final float dy = y - mLastTouchY; // change in Y

                    mPosX += dx;
                    mPosY += dy;

                    invalidate();
                */
                Log.e("ACTION_MOVE","Scale FACTOR : " + mScaleFactor);
                Log.e("ACTION_MOVE","X : " + scaledX + " Y :" + scaledY + " cX : " + cX + " cY : " + cY );
                Log.e("ACTION_MOVE","Last X : " + mLastTouchX + " Last Y :" + mLastTouchY);
                mLastTouchX = scaledX;
                mLastTouchY = scaledY;
                moveTouch(scaledX, scaledY);
                invalidate();
                break;

            
            case MotionEvent.ACTION_UP: 
                mLastTouchX = 0;
                mLastTouchY = 0;
                upTouch();
                invalidate();
            
        
        return true;
    

    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.1f, Math.min(mScaleFactor, 10.0f));
            mScaleFactor = (mScaleFactor < 1 ? 1 : mScaleFactor);
            invalidate();
            return true;
        
    
答案

您只需要将屏幕坐标转换为修改后的画布坐标:请执行以下方法:

//如果您已经移动(转移)了画布:TouchX = TouchX-translatedX;TouchY = TouchY-translationY;

//如果已缩放画布:TouchX = TouchX / scaleFactor;TouchY = TouchY / scaleFactor;

//如果您已翻译画布并对其进行缩放:TouchX =(TouchX-translatedX)/ scaleFactor;TouchY =(TouchY-translatedY)/ scaleFactor;

//然后使用此TouchX和TouchY进行绘制。

我希望这会有所帮助。

以上是关于捏缩放(绘图线)Android Canvas后获取正确的坐标的主要内容,如果未能解决你的问题,请参考以下文章

Android绘图之Canvas变换(6)

04 canvas——位移画布和旋转缩放

使用 Android 内置的手势监听器和缩放监听器实现捏缩放和拖动

android imageView:设置拖动和捏缩放参数

检测移动浏览器捏缩放

带有捏缩放的 Android 图库