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

Shr*_*hek 7 android canvas image paint pinchzoom

我通过执行以下操作在 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));
Run Code Online (Sandbox Code Playgroud)

不放大时看起来没问题。

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

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

PS:我先尝试“放大”图像,然后在图像上画线。(点击按钮或其他东西)。但这没有用,线还是很粗。

我还发现,当图像分辨率较低时,绘制的线条较粗。所以我假设在图像上绘图也与图像分辨率有关。

我正在考虑用高分辨率画布屏蔽 ImageView,但这会导致内存效率低下。另外,我对如何实际实现这一点一无所知。

我以某种方式相信这个问题的答案可以解决我的问题。

Per*_*abs 5

正确的方法是使用 View 画布动态渲染线条,而不是渲染到位图本身。

您的实现失败的原因是,如果您将网格直接渲染到位图中,那么您实际上是在更改位图像素,因此从逻辑上讲,如果缩放位图,则网格像素也会缩放,因为位图 + 网格的所有内容都已成为相同的单个图像

一种解决方案是使用任何现成的缩放图像视图小部件。您会在 GitHub 中找到很多内容,例如:

缩放图像视图

然后您有 2 个选项,扩展小部件以创建您自己的子类,或者直接在小部件代码中执行实现。你决定。

在这两种情况下,您需要做的是覆盖其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);
}
Run Code Online (Sandbox Code Playgroud)

作为旁注,避免在 onDraw 方法内创建新对象,例如 Paint 实例等,因为 onDraw 可以在短时间内多次调用。无论如何,Lint 都应该就此向您发出警告。永远不要在 onDraw、onMeasure 等方法中创建新的对象实例,因为这种情况总是预先缓存/重用它们。

一个更简单的替代方法是扩展一个视图并创建一个新的专用网格视图小部件,与实际的缩放图像视图无关。执行相同的操作,因此,也像上面的示例一样覆盖onDraw方法,并如图所示渲染网格。然后将此新视图放入您的布局设计中,正好位于缩放图像视图控件的顶部,确保两个控件具有相同的指标。