Canvas.clipPath(Path) not clipping as expected
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);
Kevin Coppock
Senior Software Engineer at Google working on Android applications. Also the developer of the Android app Holoku.
Updated on July 09, 2022Comments
-
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:
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):
So it instead seems to clip to the bounding rect of the
Path
, and not thePath
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 thisBitmap
, set that shader to aPaint
, then draw the wedge path using thatPaint
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 over 11 yearsThat 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 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 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!