Canvas.clipPath(Path) not clipping as expected

22,121

Solution 1

Are you using HC or above or otherwise using hardware acceleration?

If so, clipPath is unsupported and problematic.

developer.android.com/guide/topics/graphics/hardware-accel.html.

Solution 2

OP's question is specifically about using a clipping region and has been answered by @Simon. Bear in mind, however, that there's a more straightforward way of drawing a filled arc:

Create a Paint:

mPaint = new Paint();
mPaint.setColor(Color.BLUE);
mPaint.setStyle(Style.FILL);
mPaint.setAntiAlias(true);

When drawing, simply draw the path:

canvas.drawPath(path, mPaint);
Share:
22,121
Kevin Coppock
Author by

Kevin Coppock

Senior Software Engineer at Google working on Android applications. Also the developer of the Android app Holoku.

Updated on July 09, 2022

Comments

  • Kevin Coppock
    Kevin Coppock almost 2 years

    I'm trying to clip a canvas drawing operation to an arc-shaped wedge. However, I'm not getting the intended result after setting the clipping path to the canvas.

    For illustration, here is what I'm doing:

    enter image description here

    path.reset();
    
    //Move to point #1
    path.moveTo(rect.centerX(), rect.centerY());
    
    //Per the documentation, this will draw a connecting line from the current
    //position to the starting position of the arc (at 0 degrees), add the arc
    //and my current position now lies at #2.
    path.arcTo(rect, 0, -30);
    
    //This should then close the path, finishing back at the center point (#3)
    path.close();
    

    This works, and when I simply draw this path (canvas.drawPath(path, paint)) it draws the wedge as shown above. However, when I set this path as the canvas's clipping path and draw into it:

    //I've tried it with and without the Region.Op parameter
    canvas.clipPath(path, Region.Op.REPLACE);
    canvas.drawColor(Color.BLUE);
    

    I get the following result instead (the wedge is left just to show reference):

    enter image description here

    So it instead seems to clip to the bounding rect of the Path, and not the Path itself. Any ideas what's happening here?

    EDIT Just as an update, I've found a much more efficient way of doing this that allows for hardware acceleration. First, draw the entire image (that you'd be clipping) into an offscreen bitmap. Make a BitmapShader using this Bitmap, set that shader to a Paint, then draw the wedge path using that Paint object:

    drawMyBitmap(bitmap);
    Shader shader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
    Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
    paint.setShader(shader);
    
    @Override
    public void onDraw(Canvas canvas) {
        canvas.drawArc(rect,         //The rectangle bounding the circle
                       startAngle,   //The angle (CW from 3 o'clock) to start
                       sweepAngle,   //The angle (CW from 3 o'clock) of the arc
                       true,         //Boolean of whether to draw a filled arc (wedge)
                       paint         //The paint with the shader attached
        );
    }
    
  • Kevin Coppock
    Kevin Coppock over 11 years
    That was the problem. :) Moved the clipping part of the drawing operation into an offscreen bitmap, then drew it back to the HW accelerated canvas and it works like a charm! Thanks again!
  • Richard J. Ross III
    Richard J. Ross III about 11 years
    @kcoppock That sounds a bit backwards. Why don't you just convert the view's layer type into software, and still do your drawing in onDraw()?
  • Kevin Coppock
    Kevin Coppock about 11 years
    @RichardJ.RossIII That would have made more sense. :) I was a bit unfamiliar with that at the time. I've edited in the new way that I'm handling this problem now, thanks for the input though!