2013-03-04 83 views
1

我的问题是,我正在绘制矩形到屏幕,并希望能够在一个方向上滚动并继续绘图。这是一个基本的房屋计划绘图应用程序。画布问题 - 绘图时的滚动和缩放(保留透视图)

我开始画一个正方形:

1

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

2

话,我希望能够作出这样的:一旦

3

然而,当我点击DRAW模式开始绘制第二个房间,发生这种情况:

4

也就是说它恢复到原始缩放并绘制在错误的地方。我意识到它可能是我在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; 
     } 
    } 
} 

谁能挑开我的代码,这样我可以缩放或平移图像顺子?我吠叫错了树,我应该只使用垂直和水平滚动条吗?缩放不是绝对必要的。

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

回答

0

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

+0

啊我明白了。你会如何改变我的代码来做到这一点? – 2013-03-04 22:17:09

+0

从if语句的另一分支中取出滚动和缩放代码,并使其适用于两种模式。只要你不在另一个线程上进行背景渲染(如果你遇到性能瓶颈,你应该做的事情),在全局范围内扩展都是好的。 – 2013-03-04 22:18:57

+0

我修改了它,以便它总是包含canvas.scale和canvas.translate命令。但是,我的绘图操作现在没有被正确地抵消 - 即我仍然相对于初始缩放级别进行绘制。 – 2013-03-05 20:01:07