I've read over 20 questions/answers but I still can't get what I want. I want to cut a circle inside a rectangle as seen below:
Here is my code:
@Override
protected void onDraw(Canvas canvas) {
Paint paint = new Paint();
paint.setStyle(Paint.Style.FILL);
paint.setARGB(180, 0, 0, 0);
canvas.drawRect(0, 0, getWidth(), getHeight(), paint);
Path circularPath = new Path();
circularPath.addCircle(getWidth() / 2, getHeight() / 2, radius, Path.Direction.CCW);
canvas.clipPath(circularPath, Region.Op.REPLACE);
canvas.drawColor(0x00000000);
}
My background (setARGB
) displays correctly, however nothing is clipped. I've also tried different Op
values other than REPLACE
, forced software rasterization (as I've read on some Android versions clipPath
doesn't support some of the Op
s) by calling setLayerType(LAYER_TYPE_SOFTWARE, null);
on constructor, but no avail. How do I achieve the desired effect?
Note: My minimum SDK version is 15, so I don't need to support anything lower than 4.0.
Use clipPath
before drawRect
.
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int width = this.getWidth();
int height = this.getHeight();
mPaint.setAntiAlias(true);
mPaint.setColor(Color.WHITE);
mPaint.setStyle(Paint.Style.FILL);
canvas.drawPaint(mPaint);
float rectWidth = Utils.dpToPx(100.0f);
Path circularPath = new Path();
circularPath.addCircle(width / 2.0f, rectWidth / 2.0f, rectWidth / 3.0f, Path.Direction.CCW);
canvas.clipPath(circularPath, Region.Op.DIFFERENCE);
mPaint.setColor(Color.BLUE);
canvas.drawRect((width - rectWidth) / 2.0f, 0.0f, ((width - rectWidth) / 2.0f) + rectWidth, rectWidth, mPaint);
}
Try clipping your path in dispatchDraw()
:
@Override
protected void dispatchDraw(Canvas canvas)
{
canvas.clipPath(mClipPath, mRegion); // previously created path & region
super.dispatchDraw(canvas);
}
Remove the path clipping code from your onDraw
method, and that should do it.
Edit:
When creating your path, make sure you do so only after a measure occurred, for example:
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
mClipPath.reset();
float radius = Math.min((float)getMeasuredWidth() / 2f, (float)getMeasuredHeight() / 2f) + 5;
mClipPath.addCircle((float)getMeasuredWidth() / 2f, (float)getMeasuredHeight() / 2f, radius, Path.Direction.CCW);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With