3

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.

I made UI with SurfaceView, took Holder from it.

@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.

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

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

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

What is wrong?

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

Aleksandar G
  • 1,163
  • 2
  • 20
  • 25
tse
  • 5,769
  • 6
  • 38
  • 58

1 Answers1

7

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.

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.

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.

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

Community
  • 1
  • 1
szym
  • 5,606
  • 28
  • 34
  • More information about custom views: http://developer.android.com/training/custom-views/index.html – fadden Mar 28 '16 at 20:26