6

Fingerpaint example in sample android api demo does not draw dot/point by touching finger on screen. In code they have used Path to draw line, is there any way to draw circle or point using path?

public class MyView extends View {
    // int bh = originalBitmap.getHeight();
    // int bw = originalBitmap.getWidth();

    public MyView(Context c, int w, int h) {
        super(c);
        mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
        // Bitmap mBitmap =
        // Bitmap.createScaledBitmap(originalBitmap,200,200,true);
        mCanvas = new Canvas(mBitmap);
        mPath = new Path();
        mBitmapPaint = new Paint(Paint.DITHER_FLAG);
        //mBitmapPaint.setColor(Color.YELLOW);
        //mBitmapPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        // mBitmap = Bitmap.createBitmap(bw, bh, Bitmap.Config.ARGB_8888);
        // mCanvas = new Canvas(mBitmap);
    }


    @Override
    protected void onDraw(Canvas canvas) {
        //canvas.drawColor(customColor);
        canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
        canvas.drawPath(mPath, mPaint);
    }

    // //////************touching evants for painting**************///////
    private float mX, mY;
    private static final float TOUCH_TOLERANCE = 5;

    private void touch_start(float x, float y) {
        //mCanvas.drawCircle(x, y, progress+1, mPaint); 

        mPath.reset();          
        mPath.moveTo(x, y);
        //mPaint.setStyle(Paint.Style.FILL);
        //mPath.addCircle(x, y, (float) (progress+0.15), Direction.CW);  
        mCanvas.drawPath(mPath, mPaint);
        mX = x;
        mY = y;
        //mPaint.setStyle(Paint.Style.STROKE);

    }

    private void touch_move(float x, float y) {
        float dx = Math.abs(x - mX);
        float dy = Math.abs(y - mY);
        if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
            mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
            mX = x;
            mY = y;
        }
    }

    private void touch_up() {
        mPath.lineTo(mX, mY);
        // commit the path to our offscreen
        mCanvas.drawPath(mPath, mPaint);
        // kill this so we don't double draw
        mPath.reset();
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        float x = event.getX();
        float y = event.getY();
        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            touch_start(x, y);
            invalidate();
            break;
        case MotionEvent.ACTION_MOVE:
            touch_move(x, y);
            invalidate();
            break;
        case MotionEvent.ACTION_UP:
            touch_up();
            invalidate();
            break;
        }
        return true;
    } // end of touch events for image
}

Here is the code, what should i edit in this code to able to draw dot/point on finertouch?

Nouman Bhatti
  • 1,777
  • 4
  • 28
  • 55

5 Answers5

10

is there any way to draw circle or point using path?

Instead of trying to do that use the method drawPoint(float x, float y, Paint paint) in the class Canvas.

To use it in the API demo you will need to change 3 things:

  1. Have a private boolean mDrawPoint; in the MyView class to differentiate between a tap and a slide.
  2. Set mDrawPoint to true in touch_start() and to false in touch_move() if the path is changed (that is in the if statement).
  3. In touch_up() check the value of mDrawPoint. If it is false do what the function did before and if it is true then draw the point on the canvas: mCanvas.drawPoint(mX, mY, mPaint);

New version of touch_up():

private void touch_up() {
    if(mDrawPoint == true) {
        mCanvas.drawPoint(mX, mY, mPaint);          
    } else {
        mPath.lineTo(mX, mY);
        // commit the path to our offscreen
        mCanvas.drawPath(mPath, mPaint);
        // kill this so we don't double draw
        mPath.reset();
    }
}

when i move up my finger after drawing a line it automatically draws a point next to it, where the line ended. And when i starts a new line/curve the previously drawn line would remove /clear from the canvas leaving only dots behind that were drawn.

You don't need any more modification than what's in my answer. You probably forgot to implement a part of it.

I had the same problem when trying it up and solved it before posting my answer. It was caused because you draw on two different canvas, on given to the onDraw method, which gets lost when your finger gets up and the other is mCanvas, which is where the line is saved in touch_up. This is why touch_up has an if:

If we didn't move the finger (just tapped) then we draw the point to the mCanvas so that it is still there on the next onDraw (onDraw draws the mCanvas to the canvas it receives as argument so that older lines and points painted on mCanvas are still visible).

If we moved the finger then we save the path that was drawn to the canvas passed to onDraw to the mCanvas so that it is still present after getting the finger up.

The problem you have comes from the else part of the touch_up function never getting executed so that on touch_up a point gets drawn regardless of whether it should and the path never gets committed to mCanvas and thus disappear the next time onDraw is called.

This most likely stem from you setting mDrawPoint to true in touch_start() as I said in point 2. but forgetting to set mDrawPoint up to false in touch_move as I also said in point 2.

Here is what my touch_move looks like:

private void touch_move(float x, float y) {
    float dx = Math.abs(x - mX);
    float dy = Math.abs(y - mY);
    if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
        mPath.quadTo(mX, mY, (x + mX)/2, (y + mY)/2);
        mX = x;
        mY = y;
        mDrawPoint = false;
        }
    }
Julien Rousseau
  • 975
  • 1
  • 9
  • 15
  • By using your code i am able to draw points, but when i move up my finger after drawing a line it automatically draws a point next to it, where the line ended. And when i starts a new line/curve the previously drawn line would remove /clear from the canvas leaving only dots behind that were drawn. please suggest me what more modifications do i need to implement this? – Nouman Bhatti Jun 22 '13 at 20:11
  • @NoumanBhatti whats your exact requirement. to draw a path or a point? – Raghunandan Jun 22 '13 at 20:29
  • @Raghunandan his requirement is to draw a point when tapping and a path when sliding. The original Fingerpaint does the latter but does not draw a point if simply tapping. – Julien Rousseau Jun 23 '13 at 02:06
  • @JulienRousseau yes now i have got it. Bro you have saved my life. Thank you so much! – Nouman Bhatti Jun 23 '13 at 06:56
  • @Julein, thanks for this super-informative post. But does anyone know where the hell .. http://stackoverflow.com/q/24164334/294884 ?! thanks! – Fattie Jun 11 '14 at 13:35
1

A very late reply, but it would be easier to use mCanvas.drawPoint(x, y, mPaint); in touch_start.

user3482211
  • 446
  • 4
  • 17
1

The simple solution that works for me is just to add the following code to touch_start():

mPath.quadTo(x, y, x + 0.1f, y);
dragi
  • 3,385
  • 5
  • 22
  • 40
0

If you'd rather continue to use your path, store your ACTION_DOWN coordinates and compare them in ACTION_UP. If they haven't moved, add a tiny circle to your path.

path.addCircle(event.getX(), event.getY(), paint.getStrokeWidth()/4f, Path.Direction.CW);

The advantage of this approach is that it is simple and the circle does not look at all out of place.

Tom
  • 6,946
  • 2
  • 47
  • 63
0

The solution is very simple once one goes through the documents. I too was working on a paint (drawing with finger) app and faced the same issue. I went through the docs and found the solution. It is better to use this instead of figuring out tap vs slide.

    drawingPaint.setStrokeJoin(Paint.Join.ROUND);
    drawingPaint.setStrokeCap(Paint.Cap.ROUND);

The documents say about Stoke Join: "The Join specifies the treatment where lines and curve segments join on a stroked path. The default is MITER." This means how two adjacent points of a path should be connected together. There are three types of Join:

  1. Bevel: The outer edges of a join meet with a straight line.
  2. Miter: The outer edges of a join meet at a sharp angle.
  3. Rounded: The outer edges of a join meet in a circular arc.

Here you can probably guess why I'm using Rounded which is it will create a circular arc from one point to another adjacent point of the path. You can read more from here: https://developer.android.com/reference/android/graphics/Paint.Join

For the Stroke Cap, the documents say: "The Cap specifies the treatment for the beginning and ending of stroked lines and paths. The default is BUTT." This means how the first point and the last point of the path should be drawn. There are three types of Cap:

  1. BUTT: The stroke ends with the path, and does not project beyond it.
  2. ROUND: The stroke projects out as a semicircle, with the center at the end of the path.
  3. SQUARE: The stroke projects out as a square, with the center at the end of the path.

Using Rounded will create circles at the start and end of the path. Read this for more details: https://developer.android.com/reference/android/graphics/Paint.Cap