2013-03-04 86 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