It's supposed to be a simple whiteboard kind of tool, with zoom/panning effects.
Everything is alright with the entire drawing of the paths part, except for when it comes down to zooming/panning.
When a zoom is applied to the whiteboard, no matter the way I do, all the lines that come after the zoom applied get displaced in respect with the position I actually did the stroking.
I'll try to expose the details as good as it's possible, without showing unnecessary code, still it's quite a long post, please, bear with me.
As an image is worth a thousand words, I will illustrate the situation:
So, I've tried many different approaches, without any success.
Now down to the technical part, this is what I'm doing right now:
It's implemented extending the View.
I use the onDraw method only to perform the 'animation' of the strokes being applied:
@Override
public void onDraw(Canvas canvas)
{
super.onDraw(canvas);
if(isDrawing)
{
canvas.drawPath(mPath, mPaint);
canvas.drawBitmap(mBitmap, 0, 0, mPaint);
}
}
I have two ImageViews that I use to place the resulting bitmap right after the drawing and zooming are performed. The reason I use two views is to swap them in order to always have one available view at the drawing rendering moment.
<ImageView
android:id="@+id/imageView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:visibility="visible"
android:scaleType="matrix" />
<ImageView
android:id="@+id/imageView2"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:visibility="visible"
android:scaleType="matrix" />
After something is drawn to the canvas, I send the given bitmap to my view, then clean the canvas to set it brand new to more drawings:
private void sendImage2BackView()
{
//veeery extensive and boring code surpressed here
//set the entire hocus-pocus' resulting bitmap as a resource for my view
mView.setImageBitmap(tempBmp);
mView.bringToFront();
}
I implement a ScaleListener class that extends ScaleGestureDetector.SimpleOnScaleGestureListener
During the onScale moments, I tell my canvas what my scalling proportion is:
@Override
public boolean onScale(ScaleGestureDetector detector)
{
drawAction = ZOOM;
scaleFactor *= detector.getScaleFactor();
scaleFactor = Math.max(MIN_ZOOM, Math.min(scaleFactor, MAX_ZOOM));
canvas.setScaleFactor(scaleFactor);
return true;
}
Then, at my View ( canvas obj ), I just set the scale to the view being used:
mView.setScaleX(factor);
mView.setScaleY(factor);
Now, for the most important part, at the onScaleEnd, I call a method which I attempt to get the current canvas bitmap AS IS and send it to my view to abide peacefully with its siblings, each one its own size and offset.
public void setScaleEnd()
{
//Lots of more boring code surpressed here
//....
//I store the bitmap that was contained at the ImageView
// IF anyone is present
previousBmp = ((BitmapDrawable)mView.getDrawable()).getBitmap();
//then, I create a brand new scaled bitmap,in order to
// acquire the same proportion of ZOOM that I've just applied
tempBmp = Bitmap.createScaledBitmap(previousBmp,
(int)(mView.getWidth()*scaleFactor),
(int)(mView.getHeight()*scaleFactor), true);
int height = (int)(mView.getHeight()*scaleFactor);
int width = (int)(mView.getWidth()*scaleFactor);
//set my matrix
mMatrix = new Matrix();
//give it the right proportion
mMatrix.postScale(scaleFactor, scaleFactor);
translationX = mView.getWidth() / 2 - width / 2;
translationY = mView.getHeight() / 2 - height / 2;
//give it some necessary translation amount
mMatrix.postTranslate(translationX, translationY);
//set the matrix to the view, and send the resized bitmap to my ImageView.
mView.setImageMatrix(mMatrix);
mView.setImageBitmap(tempBmp);
}
Now, I have tried during everything I just showed straight to the canvas, giving it a scale/translate amount; tried working separately with bitmaps then sent them back to a new clean canvas.
Still I keep getting that displacement on my strokes after a given amount of ZOOM is applied!!! I just want to be able to draw; give it a zoom; then draw some more things, and have the strokes stay where I'm drawing!
Is that possible?
I was just playing with S Note app, it does exactly what I'm trying to achieve.
I want to propose some solution to you, but I'm not sure it will works.
At first I need to clarify, that you've done a big mistake in this code:
tempBmp = Bitmap.createScaledBitmap(previousBmp,
(int)(mView.getWidth()*scaleFactor),
(int)(mView.getHeight()*scaleFactor), true);
Let's assume that you have a tablet with 1280x800
pixels and scale factor 4x
or even 10x
. You will try to allocate 16Mb
and 40Mb
Bitmap accordingly!
It's so easy to get OutOfMemoryError
thrown here, so you need to use conceptually another approach.
I advice you to use Picture
class.
Canvas
object around your picture using method Picture.beginRecord(int width, int height)
onDraw()
method you need to draw your picture using method Picture.draw(Canvas canvas)
with corresponding settings (scale factor, translate) applied to canvas.I didn't try this solution, but I hope that the Picture
class will help you.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With