How to draw lines on an ImageView using canvas which are unaffected by zooming or scaling?
The correct approach is to render the lines dynamically using a View canvas, and not into the bitmap itself.
The reason why your implementation fails, is because if you render the grid directly into the bitmap, then you are effectively changing the bitmap pixels, so logically if you zoom the bitmap then the grid pixels will also zoom, as everything bitmap + grid have become the same single image.
A solution can be to use any ready-made zoom image view widget. You'll find lots in GitHub such as for example:
ZoomImageView
Then you have 2 options, to extend the widget to create your own subclass, or to perform the implementation directly into the widget code. Is up to you.
What you need to do in any of both cases, is to override its onDraw callback, and perform the grid drawing right after the super.onDraw(canvas) call. No need to create new bitmaps or new canvas instances. Use the method's canvas to perform the drawing.
@Override
protected void onDraw(final Canvas canvas) {
super.onDraw(canvas);
// Render the grid
final int slotWidth = this.getWidth() / 3;
final int slotHeight = this.getHeight() / 3;
this.paint.setColor(this.gridColor);
// Horizontal lines
canvas.drawLine(0, slotHeight, this.getWidth(), slotHeight, this.paint);
canvas.drawLine(0, (slotHeight * 2), this.getWidth(), (slotHeight * 2), this.paint);
// Vertical lines
canvas.drawLine(slotWidth, 0, slotWidth, this.getHeight(), this.paint);
canvas.drawLine((slotWidth * 2), 0, (slotWidth * 2), this.getHeight(), this.paint);
}
As a side note, avoid creating new objects inside the onDraw method, such as Paint instances, etc. as the onDraw can be called several times in a short period. Lint should warn you anyway about this. Never create new object instances in methods such as onDraw, onMeasure, etc., for such scenarios always precache/reuse them.
A simpler alternative, is to extend a View and create a new dedicated grid view widget, unrelated to the actual Zoom Image View. Perform the same, so, also override the onDraw method as the above example, and render the grid as shown. Then place this new View into your layout design, exactly on top of your Zoom Image View control, ensuring both controls have the same metrics.
Use this TouchImageView library for zooming and detecting the zoom via OnTouchImageViewListener
and isZoomed()
. If zoomed, then redraw the canvas using the zoomed area. This is the code:
touchImageView.setOnTouchImageViewListener(() -> {
if (touchImageView.isZoomed()){
//gets the zoomed area
Bitmap result = Bitmap.createBitmap(touchImageView.getWidth(), touchImageView.getHeight(), Bitmap.Config.RGB_565);
Canvas c = new Canvas(result);
touchImageView.draw(c);
}
});