2

I'm working on a drawing app. It's fairly simple, uses onTouchEvent, paths, and canvas.drawPath. Whenever the user does a quick swipe and releases without stopping, the last segment of the path blinks continuously. In the ACTION_UP condition, I update the path and set the boolean resetPath to true, and in the onDraw, I draw the path, and if resetPath is true, I call path.reset() and then set resetPath to false. What am I doing wrong?

    class DrawingPanel extends SurfaceView implements SurfaceHolder.Callback {
    private DrawingThread _thread;
    private Path path;
    private Boolean resetPath = false;

    public DrawingPanel(Context context) {
        super(context);
        getHolder().addCallback(this);
        _thread = new DrawingThread(getHolder(), this);
        path = new Path();
    }


    private float mX, mY;
    private static final float TOUCH_TOLERANCE = 25;



    public boolean onTouchEvent(MotionEvent event) {

        synchronized (_thread.getSurfaceHolder()) {
            if(event.getAction() == MotionEvent.ACTION_DOWN){
                path.reset();
                path = new Path();
                path.moveTo(event.getX(), event.getY());
                mX = event.getX();
                mY = event.getY();
            }else if(event.getAction() == MotionEvent.ACTION_MOVE){
                float dx = Math.abs(event.getX() - mX);
                float dy = Math.abs(event.getY() - mY);
                if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
                    path.quadTo(mX, mY, (event.getX() + mX)/2, (event.getY() + mY)/2);
                    mX = event.getX();
                    mY = event.getY();
                }
            }else if(event.getAction() == MotionEvent.ACTION_UP){
                resetPath = true;
            }
            return true;
        }
    }

    @Override
    public void onDraw(Canvas canvas) {
        canvas.drawPath(path, mPaint);
        if (resetPath) {
            path.reset();
            resetPath = false;
        }
    }
markthema3
  • 387
  • 2
  • 11

1 Answers1

0

Consider the following

  1. In onDraw, you are not painting or resetting the whole canvas before drawing your path. Normally, you should. If not, it always draws the path on top of the previous bitmap. If your paint was using transparency, oldest parts of the path that you draw would be less transparent than the newest parts, due to overlapping.
  2. OnTouchEvent and onDraw do not run on the same thread.
  3. SurfaceView uses transparently a double-buffering technique. Two successive calls to onDraw will draw to two different canvas. Therefore, if there is an ACTION_MOVE and ACTION_UP between the two calls to onDraw, the second buffer will have more drawing than the first. This is why you have your blinking effect.

Solution

Change resetPath to be an integer, so that you can draw the path twice before resetting it.

private int resetPath = 0;

...else if(event.getAction() == MotionEvent.ACTION_UP){
            resetPath = 2;
   }...

public void onDraw(Canvas canvas) {
    canvas.drawPath(path, mPaint);
    if (resetPath == 1) {
        path.reset();
        resetPath = 0;
    } else if(resetPath == 2) {
        resetPath = 1
    }
}
Mikaël Mayer
  • 10,425
  • 6
  • 64
  • 101