I found a function for rectangles with all 4 corners being round, but I want to have just the top 2 corners round. What can I do?
canvas.drawRoundRect(new RectF(0, 100, 100, 300), 6, 6, paint);
With canvas, use the rect() method to draw a rectangle. But, for creating a rounded rectangle, using the rect() method won't work. We will be using the lineTo() and quadraticCurveTo() method to create a rounded rectangle.
Use a path. It has the advantage of working for APIs less than 21 (Arc is also limited thusly, which is why I quad). Which is a problem because not everybody has Lollipop yet. You can however specify a RectF and set the values with that and use arc back to API 1, but then you wouldn't get to use a static (without declaring a new object to build the object).
Drawing a rounded rect:
path.moveTo(right, top + ry); path.rQuadTo(0, -ry, -rx, -ry); path.rLineTo(-(width - (2 * rx)), 0); path.rQuadTo(-rx, 0, -rx, ry); path.rLineTo(0, (height - (2 * ry))); path.rQuadTo(0, ry, rx, ry); path.rLineTo((width - (2 * rx)), 0); path.rQuadTo(rx, 0, rx, -ry); path.rLineTo(0, -(height - (2 * ry))); path.close();
As a full function:
static public Path RoundedRect(float left, float top, float right, float bottom, float rx, float ry, boolean conformToOriginalPost) { Path path = new Path(); if (rx < 0) rx = 0; if (ry < 0) ry = 0; float width = right - left; float height = bottom - top; if (rx > width/2) rx = width/2; if (ry > height/2) ry = height/2; float widthMinusCorners = (width - (2 * rx)); float heightMinusCorners = (height - (2 * ry)); path.moveTo(right, top + ry); path.rQuadTo(0, -ry, -rx, -ry);//top-right corner path.rLineTo(-widthMinusCorners, 0); path.rQuadTo(-rx, 0, -rx, ry); //top-left corner path.rLineTo(0, heightMinusCorners); if (conformToOriginalPost) { path.rLineTo(0, ry); path.rLineTo(width, 0); path.rLineTo(0, -ry); } else { path.rQuadTo(0, ry, rx, ry);//bottom-left corner path.rLineTo(widthMinusCorners, 0); path.rQuadTo(rx, 0, rx, -ry); //bottom-right corner } path.rLineTo(0, -heightMinusCorners); path.close();//Given close, last lineto can be removed. return path; }
You'd want to line all the way to those corner bits, rather than quad across them. This is what setting true to conformToOriginalPost does. Just line to the control point there.
If you want to do that all but don't care about pre-Lollipop stuff, and urgently insist that if your rx and ry are high enough, it should draw a circle.
@TargetApi(Build.VERSION_CODES.LOLLIPOP) static public Path RoundedRect(float left, float top, float right, float bottom, float rx, float ry, boolean conformToOriginalPost) { Path path = new Path(); if (rx < 0) rx = 0; if (ry < 0) ry = 0; float width = right - left; float height = bottom - top; if (rx > width/2) rx = width/2; if (ry > height/2) ry = height/2; float widthMinusCorners = (width - (2 * rx)); float heightMinusCorners = (height - (2 * ry)); path.moveTo(right, top + ry); path.arcTo(right - 2*rx, top, right, top + 2*ry, 0, -90, false); //top-right-corner path.rLineTo(-widthMinusCorners, 0); path.arcTo(left, top, left + 2*rx, top + 2*ry, 270, -90, false);//top-left corner. path.rLineTo(0, heightMinusCorners); if (conformToOriginalPost) { path.rLineTo(0, ry); path.rLineTo(width, 0); path.rLineTo(0, -ry); } else { path.arcTo(left, bottom - 2 * ry, left + 2 * rx, bottom, 180, -90, false); //bottom-left corner path.rLineTo(widthMinusCorners, 0); path.arcTo(right - 2 * rx, bottom - 2 * ry, right, bottom, 90, -90, false); //bottom-right corner } path.rLineTo(0, -heightMinusCorners); path.close();//Given close, last lineto can be removed. return path; }
So, conformToOriginalPost actually draws a rounded rect without the bottom two bits rounded.
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