如何在ImageView上使用画布绘制线条,使其不受缩放的影响?

8

我正在ImageView上绘制线条,类似于以下方式:

    Bitmap imageBitmap = ((BitmapDrawable) imageView.getDrawable()).getBitmap();
    Bitmap duplicateBitmap = Bitmap.createBitmap(imageBitmap.getWidth(),imageBitmap.getHeight(),Bitmap.Config.RGB_565);

    Canvas targetCanvas = new Canvas(duplicateBitmap);
    targetCanvas.drawBitmap(imageBitmap,0,0,null);
    Paint paint = new Paint();
    paint.setColor(Color.RED);
    paint.setStrokeWidth(3f);
    targetCanvas.drawLine(0f,100f, imageBitmap.getWidth(),100f,paint);
    imageView.setImageDrawable(new BitmapDrawable(getResources(),duplicateBitmap));

当不缩放时,看起来还不错。

但当我放大时,线条变得更粗了。(这是预期的行为)

现在,如何在图像视图上绘制线条,以便当用户缩放时,线条的粗细不受影响?

附言:我试过先"缩放"图像,然后再在图像上画线(通过点击按钮或其他方式)。但是这并没有起作用,线条仍然非常粗。

我还发现,当图像分辨率较低时,所绘制的线条会更加粗厚。因此,绘制在图像上可能与图像分辨率有关。

我想着用高分辨率的画布遮罩ImageView,但这会浪费内存。而且,我不知道如何实际实现。

我认为这个问题的答案可以解决我的问题。

2个回答

5
正确的方法是使用View画布动态地呈现线条,而不是直接渲染到位图中。 你的实现失败的原因是,如果你直接将网格渲染到位图中,那么你实际上正在改变位图像素,因此逻辑上,如果你缩放位图,那么网格像素也会缩放,因为所有的位图+网格都成为了同一张图片。 一个解决方案是使用任何现成的缩放图像视图小部件。在GitHub上可以找到很多,例如: ZoomImageView 然后你有两个选择,要么扩展小部件以创建自己的子类,要么直接在小部件代码中执行实现。由你决定。 在这两种情况下,你需要做的是覆盖它的onDraw回调,并在super.onDraw(canvas)调用之后执行网格绘制。 无需创建新的位图或新的画布实例。使用该方法的画布进行绘制。
@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);
}

作为一个附注,避免在onDraw方法中创建新对象,如Paint实例等,因为onDraw可能会在短时间内被多次调用。Lint应该会警告你的。永远不要在onDraw、onMeasure等方法中创建新的对象实例,对于这样的情况,总是预缓存/重用它们。
一个更简单的选择是扩展View并创建一个新的专用网格视图小部件,与实际的Zoom Image View无关。执行相同的操作,覆盖上面示例中的onDraw方法,并呈现网格。然后将此新视图放入您的布局设计中,正好位于Zoom Image View控件的顶部,确保两个控件具有相同的度量标准。

2
使用TouchImageView库来实现缩放和通过OnTouchImageViewListenerisZoomed()检测缩放。如果已缩放,则使用缩放区域重新绘制画布。代码如下:
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);
    }
});

没有,没有任何区别。 - Shreemaan Abhishek

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接