1
我的問題是,我正在繪製矩形到屏幕,並希望能夠在一個方向上滾動並繼續繪圖。這是一個基本的房屋計劃繪圖應用程序。畫布問題 - 繪圖時的滾動和縮放(保留透視圖)
我開始畫一個正方形:
我然後單擊移動屏幕按鈕,切換到「移動模式」。我捏縮小繪製相鄰房間:
話,我希望能夠作出這樣的:一旦
然而,當我點擊DRAW模式開始繪製第二個房間,發生這種情況:
也就是說它恢復到原始縮放並繪製在錯誤的地方。我意識到它可能是我在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;
}
}
}
誰能挑開我的代碼,這樣我可以縮放或平移圖像順子?我吠叫錯了樹,我應該只使用垂直和水平滾動條嗎?縮放不是絕對必要的。
任何幫助將不勝感激!謝謝。
啊我明白了。你會如何改變我的代碼來做到這一點? – 2013-03-04 22:17:09
從if語句的另一分支中取出滾動和縮放代碼,並使其適用於兩種模式。只要你不在另一個線程上進行背景渲染(如果你遇到性能瓶頸,你應該做的事情),在全局範圍內擴展都是好的。 – 2013-03-04 22:18:57
我修改了它,以便它總是包含canvas.scale和canvas.translate命令。但是,我的繪圖操作現在沒有被正確地抵消 - 即我仍然相對於初始縮放級別進行繪製。 – 2013-03-05 20:01:07