Note that there are some explanatory texts on larger screens.

plurals
  1. POAndroid - canvas confusion (drawing and scrolling)
    text
    copied!<p>I'm having a bit of confusion with <code>canvas</code> in android and was wondering if someone could clarify a few things for me.</p> <p>I currently have this code inside my View class:</p> <pre><code> 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 BitmapDrawable mImage; 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 setHorizontalScrollBarEnabled(true); setVerticalScrollBarEnabled(true); TypedArray a = context.obtainStyledAttributes(R.styleable.View); initializeScrollbars(a); a.recycle(); computeVerticalScrollRange(); computeHorizontalScrollRange(); mImage = new BitmapDrawable(getResources(), myBitmap); 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) { 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(); System.out.println("X: " + mPosX + " Y: " + mPosY); canvas.translate(mPosX, mPosY); canvas.scale(mScaleFactor, mScaleFactor); mImage.draw(canvas); canvas.restore(); } </code></pre> <p>This is kind of an amalgamation of 2 different approaches to drawing to the screen as I understand it. My understanding is that I have <code>myBitmap</code> (which is what users drawings are drawn on) and this works fine for <em>"addObjectMode"</em>. However, <em>"moveMode"</em> is when I want the users to be able to pinch zoom scroll etc. around the house plan that they have drawn. </p> <p>Currently, I am able to draw objects fine but when I press the button to enable <code>moveMode</code>, the drawing disappears when I touch or gesture. I'm aware this is probably because of the code in <code>onDraw()</code>; but canvas's are still a bit of a mystery to me. </p> <p>Eventually, I'm going to want a basic undo/redo feature as well as saving the <code>canvas/bitmap</code> to be opened later. Can anyone offer any advice or link to any comprehensive canvas tutorials?</p> <p>EDIT: it might be useful to include my <code>onTouchEvent</code> methods too-</p> <pre><code> public boolean onTouchEvent(MotionEvent event) { // on any touch event if (addObjectMode == 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 &amp; 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); 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() &amp; MotionEvent.ACTION_POINTER_INDEX_MASK) &gt;&gt; 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; } } return true; } else { return false; } } </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload