如何从SurfaceView绘制到Canvas?

时间:2022-08-02 21:19:00

I'm trying to do simple painter. The problem that it looks like Android has three independent Canvas and give me it for drawing sequentially.

我正在努力做一个简单的画家。它看起来像Android有三个独立的Canvas的问题,并给我顺序绘制。

I made UI with SurfaceView, took Holder from it.

我使用SurfaceView制作了UI,从中获取了Holder。

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    sv = (SurfaceView) findViewById(R.id.sv);
    holder = sv.getHolder();

    holder.addCallback(callback);
}

Then took Surface.

然后拿了Surface。

@Override
    public void surfaceCreated(SurfaceHolder holder) {
    surface = holder.getSurface();
}

And by events from OnTouchListener() draw dots and lines.

通过OnTouchListener()的事件绘制点和线。

private void paintStartDot(float x, float y) {
    Canvas canvas = surface.lockCanvas(null);

    canvas.drawPoint(x, y, drawPaint);
    surface.unlockCanvasAndPost(canvas);

    lastX = x;
    lastY = y;
}

private void paintEndDot(float x, float y) {
    Canvas canvas = surface.lockCanvas(null);

    canvas.drawLine(lastX, lastY, x, y, drawPaint);

    surface.unlockCanvasAndPost(canvas);

    lastX = x;
    lastY = y;
}

The screencast:

截屏视频:

https://youtu.be/NNDnzrtMLZI

https://youtu.be/NNDnzrtMLZI

What is wrong?

哪里不对?

Full source is available here: https://github.com/tseglevskiy/canvasdemo1/blob/error/app/src/main/java/ru/jollydroid/canvasdemo1/MainActivity.java

完整资源来源:https://github.com/tseglevskiy/canvasdemo1/blob/error/app/src/main/java/ru/jollydroid/canvasdemo1/MainActivity.java

1 个解决方案

#1


5  

The Canvas that Surface.lockCanvas gives you is not persistent. The moment you call unlockCanvasAndPost, the contents of the surface buffer are pushed out to the screen. Every time you call lockCanvas you need to redraw the picture from scratch.

Surface.lockCanvas为您提供的Canvas不是持久性的。调用unlockCanvasAndPost时,表面缓冲区的内容将被推送到屏幕。每次调用lockCanvas时,都需要从头开始重绘图片。

If you want to update the canvas incrementally, you should keep an "off-screen" canvas backed by a Bitmap that you update in response to user actions. Then paint the bitmap to the Surface canvas.

如果要以增量方式更新画布,则应保留一个“Bit-screen”画布,该画布由您为响应用户操作而更新的Bitmap支持。然后将位图绘制到Surface画布。

private void paintStartDot(float x, float y) {
    if (mBitmap == null) return;  // not ready yet
    Canvas canvas = new Canvas(mBitmap);
    canvas.drawPoint(x, y, drawPaint);

    // draw the bitmap to surface 
    canvas = surface.lockCanvas(null);
    canvas.drawBitmap(mBitmap, 0, 0, null);
    surface.unlockCanvasAndPost(canvas);
}

@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
    // good place to create the Bitmap
    mBitmap = Bitmap.createBitmap(width, height, Bitmap.Config. ARGB_8888);
    // also here we need to transform the old bitmap to new one
}

I'm not sure if you really need a SurfaceView. You could just extend the View and override its View.onDraw method. In that case, call view.invalidate() to indicate it needs to be redrawn.

我不确定你是否真的需要SurfaceView。您可以只扩展View并覆盖其View.onDraw方法。在这种情况下,请调用view.invalidate()以指示需要重绘。

See also: Android View.onDraw() always has a clean Canvas

另请参阅:Android View.onDraw()始终具有干净的Canvas

#1


5  

The Canvas that Surface.lockCanvas gives you is not persistent. The moment you call unlockCanvasAndPost, the contents of the surface buffer are pushed out to the screen. Every time you call lockCanvas you need to redraw the picture from scratch.

Surface.lockCanvas为您提供的Canvas不是持久性的。调用unlockCanvasAndPost时,表面缓冲区的内容将被推送到屏幕。每次调用lockCanvas时,都需要从头开始重绘图片。

If you want to update the canvas incrementally, you should keep an "off-screen" canvas backed by a Bitmap that you update in response to user actions. Then paint the bitmap to the Surface canvas.

如果要以增量方式更新画布,则应保留一个“Bit-screen”画布,该画布由您为响应用户操作而更新的Bitmap支持。然后将位图绘制到Surface画布。

private void paintStartDot(float x, float y) {
    if (mBitmap == null) return;  // not ready yet
    Canvas canvas = new Canvas(mBitmap);
    canvas.drawPoint(x, y, drawPaint);

    // draw the bitmap to surface 
    canvas = surface.lockCanvas(null);
    canvas.drawBitmap(mBitmap, 0, 0, null);
    surface.unlockCanvasAndPost(canvas);
}

@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
    // good place to create the Bitmap
    mBitmap = Bitmap.createBitmap(width, height, Bitmap.Config. ARGB_8888);
    // also here we need to transform the old bitmap to new one
}

I'm not sure if you really need a SurfaceView. You could just extend the View and override its View.onDraw method. In that case, call view.invalidate() to indicate it needs to be redrawn.

我不确定你是否真的需要SurfaceView。您可以只扩展View并覆盖其View.onDraw方法。在这种情况下,请调用view.invalidate()以指示需要重绘。

See also: Android View.onDraw() always has a clean Canvas

另请参阅:Android View.onDraw()始终具有干净的Canvas