I am trying to make a painting app. Zoom kinda works, when i try to draw on canvas after the zoom, it does not draw on the location of the finger. instead it draws scale to the device screen.
I did some research but could not find the answer to the solution. -> float x = (event.getX() - scalePointX)/mScaleFactor; // does not work,
I tried to implement matrix but was unsuccessful. Can someone please help me to draw on the finger when the canvas is zoomed in or out?
Thank you!
public class paintView extends View {
Paint paint;
Path path;
Bitmap bitmap;
Canvas mcanvas;
private final float TOUCH_TOLERANCE = 4;
private float mX, mY;
public static final int DEFAULT_BG_COLOR = Color.WHITE;
private int backgroundColor = DEFAULT_BG_COLOR;
private ArrayList<FingerPath> paths = new ArrayList<>();
private Paint mBitmapPaint = new Paint(Paint.DITHER_FLAG);
private final ScaleGestureDetector mScaleGesture;
private float mScaleFactor = 1.f;
private float mPosX;
private float mPosY;
private float scalePointX, scalePointY;
private Rect clipBounds_canvas;
public paintView(Context context) {
this(context, null);
}
public paintView(Context context, AttributeSet attrs){
super(context, attrs);
mScaleGesture = new ScaleGestureDetector(context, new ScaleListener());
paint = new Paint();
paint.setAntiAlias(true);
paint.setColor(Color.BLACK);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(8f);
}
public void init(DisplayMetrics metrics){
int height = metrics.heightPixels;
int width = metrics.widthPixels;
bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
mcanvas = new Canvas(bitmap);
}
@Override
protected void onDraw(Canvas canvas) {
canvas.save();
mcanvas.drawColor(backgroundColor);
clipBounds_canvas = canvas.getClipBounds();
for(FingerPath fp: paths){
paint.setMaskFilter(null);
mcanvas.drawPath(fp.path, paint);
}
canvas.translate(mPosX, mPosY);
canvas.scale(mScaleFactor, mScaleFactor,scalePointX,scalePointY);
canvas.drawBitmap(bitmap, 0, 0, mBitmapPaint);
canvas.restore();
}
private void touchStart(float x, float y){
path = new Path();
FingerPath fp = new FingerPath(path);
paths.add(fp);
path.reset();
path.moveTo(x,y);
mX = x;
mY = y;
}
private void touchMove(float x, float y){
float dx = Math.abs(x - mX);
float dy = Math.abs(y - mY);
if(dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE ){
path.quadTo(mX, mY, (x+mX)/2, (y+mY)/2);
mX = x;
mY = y;
}
}
private void touchUp(){
path.lineTo(mX,mY);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
final float x = (event.getX() - scalePointX)/mScaleFactor;
final float y = (event.getY() - scalePointY)/mScaleFactor;
mScaleGesture.onTouchEvent(event);
final int action = event.getAction();
switch(action & MotionEvent.ACTION_MASK){
case MotionEvent.ACTION_DOWN:
touchStart(x, y);
invalidate();
break;
case MotionEvent.ACTION_MOVE:
touchMove(x,y);
invalidate();
break;
case MotionEvent.ACTION_UP:
touchUp();
invalidate();
break;
}
return true;
}
public class FingerPath {
public Path path;
public FingerPath(Path path) {
this.path = path;
}
}
private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
@Override
public boolean onScale(ScaleGestureDetector detector) {
mScaleFactor *= detector.getScaleFactor();
scalePointX = detector.getFocusX();
scalePointY = detector.getFocusY();
// Don't let the object get too small or too large.
mScaleFactor = Math.max(0.5f, Math.min(mScaleFactor, 3.0f));
//zoom out 'up to' the size of canvas(screen size)
//mScaleFactor = (mScaleFactor < 1 ? 1 : mScaleFactor);
invalidate();
return true;
}
@Override
public boolean onScaleBegin(ScaleGestureDetector detector) {
return true;
}
}
}