I'm trying to draw using onTouch events on a Canvas over an Imageview that is pinchable/zoomable. It works perfectly if the image is fullscreen (and proportioned to the size of the screen), but once you zoom in on the image, the drawing point is not the same place as where you touch the screen.
I am creating a canvas and an imageview like so:
canvas = new Canvas(bitmap);
image.setImageBitmap(bitmap);
and then performing a lot of pinch/zoom transformations by using setMatrix
on image
. By looking at bitmap.getHeight()
and bitmap.getWidth()
, it's evident that throughout all the transformations, neither Bitmap
nor Image
actually change in size. Image, for instance, stays at a constant 2560x1454
while Bitmap stays at 3264x1836
(using image.getHeight()/width()
and bitmap.getHeight()/width()
for those values).
For the drawing part, I'm converting MotionEvent
to a series of Point objects (literally just int x
, int y
) and then translating that value through a formula I found somewhere on the internet. I really have no idea why it works, which is probably my first problem.
List<Point> points = new ArrayList<>();
private boolean handleDraw(View v, MotionEvent event) {
if (event.getAction() != MotionEvent.ACTION_UP) {
Point p = new Point();
p.x = event.getX();
p.y = event.getY();
convertPoint(p, v);
points.add(p);
//draw the converted points
drawOnBitmap();
return true;
} else if (event.getAction() == MotionEvent.ACTION_UP) {
points.clear();
return true;
}
return true;
}
and then they are converted into bitmap values here
//v here is the view passed by the ontouch listener.
private void convertPoint(Point point, View v) {
double divisor = ((double) bitmap.getWidth() / (double) v.getWidth());
point.x = (int) ((double) point.x * divisor);
point.y = (int) ((double) point.y * divisor);
}
and drawn onto the canvas here:
private void drawOnBitmap() {
Path path = new Path();
boolean first = true;
//uses quaddraw
for (int i = 0; i < points.size(); i += 2) {
Point point = points.get(i);
if (first) {
first = false;
path.moveTo(point.x, point.y);
} else if (i < points.size() - 1) {
Point next = points.get(i + 1);
path.quadTo(point.x, point.y, next.x, next.y);
} else {
path.lineTo(point.x, point.y);
}
}
canvas.drawPath(path, redPaint);
image.invalidate();
}
with Paint being
redPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
redPaint.setStyle(Paint.Style.STROKE);
redPaint.setStrokeWidth(STROKE_WIDTH);
redPaint.setColor(Color.RED);
In general, what's happening is that the touch event is being scaled from the size of the screen to the size of the bitmap (see the above image for an example). However, the answer isn't to just take the original getRaw()
values; those are always incorrect.
I guess the question is, how do I get the canvas to respond to the ABSOLUTE position of the touch event instead of the proportional one? Failing that, how can I transform the base canvas with the same values as the imageview and get them both to scale proportionally?