Android 画布问题&x2014;绘制时滚动和缩放(保留透视图)

Android 画布问题&x2014;绘制时滚动和缩放(保留透视图),android,android-canvas,Android,Android Canvas,我的问题是,我在屏幕上绘制矩形,希望能够在一个方向上滚动并继续绘制。这是一个基本的房屋平面图应用程序 我先画一个正方形: 然后单击移动屏幕按钮并切换到“移动模式”。我将缩小以绘制相邻房间: 然后我想画出这个: 但是,只要单击“绘制模式”并开始绘制第二个房间,就会发生以下情况: 即,它恢复到原始缩放并在错误的位置绘制。我意识到这可能是我在onDraw()方法中的代码。这是我的密码: class HomerView extends View { // the custom View for

我的问题是,我在屏幕上绘制矩形,希望能够在一个方向上滚动并继续绘制。这是一个基本的房屋平面图应用程序

我先画一个正方形:

然后单击移动屏幕按钮并切换到“移动模式”。我将缩小以绘制相邻房间:

然后我想画出这个:

但是,只要单击“绘制模式”并开始绘制第二个房间,就会发生以下情况:

即,它恢复到原始缩放并在错误的位置绘制。我意识到这可能是我在
onDraw()
方法中的代码。这是我的密码:

class HomerView extends View { // the custom View for drawing on

    // set up Bitmap, canvas, path and paint
    private Bitmap myBitmap; // the initial image we turn into our canvas
    private Canvas myCanvas; // the canvas we are drawing on
    private Rect myRect; // the mathematical path of the lines we draw
    private Paint myBitmapPaint; // the paint we use to draw the bitmap

    // get the width of the entire tablet screen
    private int screenWidth = getContext().getResources().getDisplayMetrics().widthPixels;
    // get the height of the entire tablet screen
    private int screenHeight = getContext().getResources().getDisplayMetrics().heightPixels;

    private int mX, mY, iX, iY; // current x,y and initial x,y
    private static final float TOUCH_TOLERANCE = 4;
    private static final int INVALID_POINTER_ID = -1;
    private float mPosX;
    private float mPosY;
    private float mLastTouchX;
    private float mLastTouchY;
    private int mActivePointerId = INVALID_POINTER_ID;
    private ScaleGestureDetector mScaleDetector;
    private float mScaleFactor = 1.f;

    public HomerView(Context context) { // constructor of HomerView
        super(context);
        myBitmap = Bitmap.createBitmap(screenWidth, screenHeight,
                Bitmap.Config.ARGB_8888); // set our drawable space - the bitmap
                                          // which becomes the canvas we draw on
        myCanvas = new Canvas(myBitmap); // set our canvas to our bitmap which
                                         // we just set up
        myRect = new Rect(); // make a new rect
        myBitmapPaint = new Paint(Paint.DITHER_FLAG); // set dither to ON in our
                                                      // saved drawing - gives
                                                      // better color
                                                      // interaction
        mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
    }

    public HomerView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
    }

    public HomerView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    protected void onDraw(Canvas canvas) { // method used when we want to draw
                                           // something to our canvas
        super.onDraw(canvas);
        if (addObjectMode == true || addApplianceMode == true) {
            canvas.drawColor(Color.TRANSPARENT); // sets canvas colour
            canvas.drawBitmap(myBitmap, 0, 0, myBitmapPaint); // save the canvas
                                                              // to bitmap - the
                                                              // numbers are the
                                                              // x, y coords we
                                                              // are drawing
                                                              // from
            canvas.drawRect(myRect, myPaint); // draw the rectangle that the
                                              // user has drawn using the paint
                                              // we set up
        } else if (moveMode == true) {
            canvas.save();
            canvas.translate(mPosX, mPosY);
            canvas.scale(mScaleFactor, mScaleFactor);
            canvas.drawBitmap(myBitmap, 0, 0, myBitmapPaint); // if not present
                                                              // - nothing is
                                                              // moved
            canvas.restore();
        }
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) { // if
                                                                     // screen
                                                                     // size
                                                                     // changes,
                                                                     // alter
                                                                     // the
                                                                     // bitmap
                                                                     // size
        super.onSizeChanged(w, h, oldw, oldh);
    }

    private void touch_Start(float x, float y) { // on finger touchdown
        // check touch mode
        iX = (int) (Math.round(x));
        iY = (int) (Math.round(y));
        mX = (int) (Math.round(x));
        mY = (int) (Math.round(y));
        if (addObjectMode == true) {
            myRect.set(iX, iY, mX, mY);
        } else if (addApplianceMode == true) {
            // code to draw an appliance icon at mX, mY (with offset so icon is
            // centered)
            if (isLamp == true) {
                Resources res = getResources();
                bmp = BitmapFactory.decodeResource(res, R.drawable.lamp);
                myCanvas.drawBitmap(bmp, iX - 50, iY - 50, myBitmapPaint);
            } else if (isPC == true) {
                Resources res = getResources();
                bmp = BitmapFactory.decodeResource(res, R.drawable.pc);
                myCanvas.drawBitmap(bmp, iX - 50, iY - 50, myBitmapPaint);
            } else if (isKettle == true) {
                Resources res = getResources();
                bmp = BitmapFactory.decodeResource(res, R.drawable.kettle);
                myCanvas.drawBitmap(bmp, iX - 50, iY - 50, myBitmapPaint);
            } else if (isOven == true) {
                Resources res = getResources();
                bmp = BitmapFactory.decodeResource(res, R.drawable.oven);
                myCanvas.drawBitmap(bmp, iX - 50, iY - 50, myBitmapPaint);
            } else if (isTV == true) {
                Resources res = getResources();
                bmp = BitmapFactory.decodeResource(res, R.drawable.tv);
                myCanvas.drawBitmap(bmp, iX - 50, iY - 50, myBitmapPaint);
            }
        }
    }

    private void touch_Move(float x, float y) { // on finger movement
        float dX = Math.abs(x - mX); // get difference between x and my X
        float dY = Math.abs(y - mY);
        if (dX >= TOUCH_TOLERANCE || dY >= TOUCH_TOLERANCE) { // if coordinates
                                                              // are outside
                                                              // screen? if
                                                              // touching hard
                                                              // enough?
            mX = (int) (Math.round(x));
            mY = (int) (Math.round(y));
            if (addObjectMode == true) {
                myRect.set(iX, iY, mX, mY);
            }
        }
    }

    @SuppressWarnings("deprecation")
    private void touch_Up() { // on finger release
        if (addObjectMode == true) {
            myRect.set(iX, iY, mX, mY);
            myCanvas.drawRect(iX, iY, mX, mY, myPaint);
            if (eraseMode == false) {
                dialogStarter();
            }
        } else if (addApplianceMode == true) {
            showDialog(DIALOG_DEVICE_ENTRY);
        }
    }

    public boolean onTouchEvent(MotionEvent event) { // on any touch event
        if (addObjectMode == true || addApplianceMode == true) {

            float x = event.getX(); // get current X
            float y = event.getY(); // get current Y

            switch (event.getAction()) { // what action is the user performing?
            case MotionEvent.ACTION_DOWN: // if user is touching down
                touch_Start(x, y);
                invalidate();
                break;
            case MotionEvent.ACTION_MOVE: // if user is moving finger while
                                          // touched down
                touch_Move(x, y);
                invalidate();
                break;
            case MotionEvent.ACTION_UP: // if user has released finger
                touch_Up();
                invalidate();
                break;
            }
            return true;
        } else if (moveMode == true) {
            mScaleDetector.onTouchEvent(event);
            final int action = event.getAction();
            switch (action & MotionEvent.ACTION_MASK) {
            case MotionEvent.ACTION_DOWN: {
                final float x = event.getX();
                final float y = event.getY();
                mLastTouchX = x;
                mLastTouchY = y;
                mActivePointerId = event.getPointerId(0);
                invalidate();
                break;
            }
            case MotionEvent.ACTION_MOVE: {
                final int pointerIndex = event
                        .findPointerIndex(mActivePointerId);
                final float x = event.getX(pointerIndex);
                final float y = event.getY(pointerIndex);

                // Only move if the ScaleGestureDetector isn't processing a
                // gesture.
                if (!mScaleDetector.isInProgress()) {
                    final float dx = x - mLastTouchX;
                    final float dy = y - mLastTouchY;
                    mPosX += dx;
                    mPosY += dy;
                    invalidate();
                }
                mLastTouchX = x;
                mLastTouchY = y;
                break;
            }

            case MotionEvent.ACTION_UP: {
                mActivePointerId = INVALID_POINTER_ID;
                break;
            }

            case MotionEvent.ACTION_CANCEL: {
                mActivePointerId = INVALID_POINTER_ID;
                break;
            }

            case MotionEvent.ACTION_POINTER_UP: {
                final int pointerIndex = (event.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
                final int pointerId = event.getPointerId(pointerIndex);
                if (pointerId == mActivePointerId) {
                    // This was our active pointer going up. Choose a new
                    // active pointer and adjust accordingly.
                    final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
                    mLastTouchX = event.getX(newPointerIndex);
                    mLastTouchY = event.getY(newPointerIndex);
                    mActivePointerId = event.getPointerId(newPointerIndex);
                }
                break;
            }
            }
            invalidate();
            return true;
        } else {
            return false;
        }
    }

    public void drawApplianceIcon() {
        myCanvas.drawBitmap(bmp, iX - 50, iY - 50, myBitmapPaint);
        makeToast("BMP drawn to canvas = " + bmp);
    }

    private 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, 10.0f));
            invalidate();
            return true;
        }
    }
}
有人能把我的代码拆开,这样我就可以直接在缩放或平移的图像上画画了吗?我是不是选错了树,我应该只使用垂直和水平滚动条吗?缩放并不是绝对必要的


任何帮助都将不胜感激!谢谢。

您的onDraw在非移动模式下不会缩放画布。这意味着,一旦进入任何其他模式,就会永久丢失比例因子。您需要解决这个问题。

从if语句的另一个分支获取滚动和缩放代码,并使其应用于两种模式。只要您没有在另一个线程上进行背景渲染(只有在遇到性能瓶颈时才应该这样做),全局缩放就可以了。我对其进行了修改,使其始终包含canvas.scale和canvas.translate命令。但是,我的绘图操作现在没有正确偏移-即,我仍然相对于初始缩放级别进行绘图。您可能还需要缩放矩形。