How to draw a partial round rect on a android canvas? - android

I want to draw on a canvas a round rectangle fill with color (or bitmap) and with a stroke but without some selected corners and also without the border on some selected sides. any ideas how i can achieve this ?

you can split the drawing process into two parts.
draw the fill area
when trying to draw a shape that is not support by the standard sdk APIs, Canvas.drawPath method will be a good way to do it.you can just define four variables to represent radiuses of four corners.
Path path = new Path();
Rect drawingRect = {the rect area you want to draw}
RectF topLeftArcBound = new RectF();
RectF topRightArcBound = new RectF();
RectF bottomLeftArcBound = new RectF();
RectF bottomRightArcBound = new RectF();
topRightArcBound.set(drawingRect.right - topRightRadius * 2, drawingRect.top, drawingRect.right, drawingRect.top + topRightRadius * 2);
bottomRightArcBound.set(drawingRect.right - bottomRightRadius * 2, drawingRect.bottom - bottomRightRadius * 2, drawingRect.right, drawingRect.bottom);
bottomLeftArcBound.set(drawingRect.left, drawingRect.bottom - bottomLeftRadius * 2, drawingRect.left + bottomLeftRadius * 2, drawingRect.bottom);
topLeftArcBound.set(drawingRect.left, drawingRect.top, drawingRect.left + topLeftRadius * 2, drawingRect.top + topLeftRadius * 2);
path.reset();
path.moveTo(drawingRect.left + topLeftRadius, drawingRect.top);
//draw top horizontal line
path.lineTo(drawingRect.right - topRightRadius, drawingRect.top);
//draw top-right corner
path.arcTo(topRightArcBound, -90, 90);
//draw right vertical line
path.lineTo(drawingRect.right, drawingRect.bottom - bottomRightRadius);
//draw bottom-right corner
path.arcTo(bottomRightArcBound, 0, 90);
//draw bottom horizontal line
path.lineTo(drawingRect.left - bottomLeftRadius, drawingRect.bottom);
//draw bottom-left corner
path.arcTo(bottomLeftArcBound, 90, 90);
//draw left vertical line
path.lineTo(drawingRect.left, drawingRect.top + topLeftRadius);
//draw top-left corner
path.arcTo(topLeftArcBound, 180, 90);
path.close();
paint.setStyle(Paint.Style.FILL);
canvas.drawPath(path, paint);
and you can just set radius to zero for selected corners
draw border
border contains eight parts:
top-left corner
top line
top-right corner
right line
bottom-right corner
bottom line
bottom-left corner
left line
use a int value to contains selected parts will be a good idea
private static final int TOP_LEFT_CORNER = 0x1;
private static final int TOP_LINE = 0x2;
private static final int TOP_RIGHT_CORNER = 0x4;
private static final int RIGHT_LINE = 0x8;
private static final int BOTTOM_RIGHT_CORNER = 0x10;
private static final int BOTTOM_LINE = 0x20;
private static final int BOTTOM_LEFT_CORNER = 0x40;
private static final int LEFT_LINE = 0x80;
private int selectedParts = TOP_LEFT_CORNER | TOP_LINE | TOP_RIGHT_CORNER;
and now we can draw border based on selectedParts:
paint.setStyle(Paint.Style.STROKE);
if((selectedParts & TOP_LINE) > 0){
canvas.drawLine(drawingRect.left + topLeftRadius, drawingRect.top, drawingRect.right - topRightRadius, drawingRect.top);
}
if((selectedParts & TOP_RIGHT_CORNER) > 0){
canvas.drawArc(topRightArcBound, -90, 90, false, paint);
}
if((selectedParts & RIGHT_LINE) > 0){
canvas.drawLine(drawingRect.right, drawingRect.top + topRightRadius, drawingRect.right, drawingRect.bottom - bottomRightRadius, paint);
}
if((selectedParts & BOTTOM_RIGHT_CORNER) > 0){
canvas.drawArc(bottomRightArcBound, 0, 90, false, paint);
}
if((selectedParts & BOTTOM_LINE) > 0){
canvas.drawLine(drawingRect.right - bottomRightRadius, drawingRect.bottom. drawingRect.left + bottomLeftRadius, drawingRect.bottom, paint);
}
if((selectedParts & BOTTOM_LEFT_CORNER) > 0){
canvas.drawArc(bottomLeftArcBound, 90, 90, false, paint);
}
if((selectedParts & LEFT_LINE) > 0){
canvas.drawLine(drawingRect.left, drawingRect.bottom - bottomLeftRadius, drawingRect.left, drawingRect.top + topLeftRadius, paint);
}
if((selectedParts & TOP_LEFT_CORNER) > 0){
canvas.drawArc(topLeftArcBound, 180, 90, false, paint);
}

Related

draw rounded corner inside rectangle

I designed one view in which i have rounded corners. and inside that view i have other view. i give rounded corners to stroke but its not effecting inside box. you can view in below screenshot.
you can see in both inside corners. there are not properly rounded shape.
so how can I do that with proper rounded shape?
below is code:
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setColor(mBorderColor);
paint.setStyle(Style.STROKE);
float strokeWidth = mHeight / 30.0f;
float strokeWidth2 = strokeWidth / 2;
paint.setStrokeWidth(strokeWidth);
int space = 3;
int headHeight = (int) (strokeWidth + 10.5f);
Path strokepath = RoundedRect(strokeWidth2, headHeight + strokeWidth2, mWidth - strokeWidth2, mHeight - strokeWidth2, 15, 15,
true, true, true, true);
canvas.drawPath(strokepath, paint);
Path fillpath = RoundedRect(strokeWidth+space, headHeight + strokeWidth + topOffset-space, mWidth - strokeWidth-space, mHeight - strokeWidth-space, 15, 15,
true, true, true, true);
canvas.drawPath(fillpath, mViewPaint);
paint.setStyle(Style.FILL);
public static Path RoundedRect(
float left, float top, float right, float bottom, float rx, float ry,
boolean tl, boolean tr, boolean br, boolean bl) {
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);
if (tr)
path.rQuadTo(0, -ry, -rx, -ry);//top-right corner
else {
path.rLineTo(0, -ry);
path.rLineTo(-rx, 0);
}
path.rLineTo(-widthMinusCorners, 0);
if (tl)
path.rQuadTo(-rx, 0, -rx, ry); //top-left corner
else {
path.rLineTo(-rx, 0);
path.rLineTo(0, ry);
}
path.rLineTo(0, heightMinusCorners);
if (bl)
path.rQuadTo(0, ry, rx, ry);//bottom-left corner
else {
path.rLineTo(0, ry);
path.rLineTo(rx, 0);
}
path.rLineTo(widthMinusCorners, 0);
if (br)
path.rQuadTo(rx, 0, rx, -ry); //bottom-right corner
else {
path.rLineTo(rx, 0);
path.rLineTo(0, -ry);
}
path.rLineTo(0, -heightMinusCorners);
path.close();//Given close, last lineto can be removed.
return path;
}
With the way that corners are drawn, the inner part of the corner will always be of a smaller radii than the outer part of the corner. To get the right radii for the inner part you have to draw it onto the screen. In this case you have to draw the space between the Stoke Path and the Fill Path. The code below is what is needed to draw the space, if mViewPaint does not have a stroke width.
Paint spacePaint = new Paint();
spacePaint.setAntiAlias(true);
spacePaint.setColor(mBackground);
spacePaint.setStyle(Paint.Style.STROKE);
spacePaint.setStrokeWidth(space*2);
Path spacepath = RoundedRect(strokeWidth + space,
headHeight + strokeWidth + topOffset-space,
mWidth - strokeWidth - space,
mHeight - strokeWidth - space,
15, 15,
true, true, true, true);
canvas.drawPath(spacepath, spacePaint);
You also have to change the following line for this to work
paint.setStyle(Paint.Style.STROKE);
to
paint.setStyle(Paint.Style.FILL_AND_STROKE);
Now as others have suggested you could have used either Canvas.drawRoundRect() or Path.addRoundRect and they would have done the same thing as your method RoundedRect.

android canvas draw text in the triangle

In this Image I want text to totally be in the triangle with CYAN color.
I have created my own ImageView:
public class BookImageView extends android.support.v7.widget.AppCompatImageView {
private static final Float DISCOUNT_SIDE_SIZE = 0.33333F;
private Bitmap bitmap;
private Paint drawPaint = new Paint();
private Paint trianglePaint = new Paint();
{
trianglePaint.setColor(Constants.DISCOUNT_COLOR);
trianglePaint.setStyle(Paint.Style.FILL);
trianglePaint.setShadowLayer(10.0f, 10.0f, 10.0f, Color.parseColor("#7f000000"));
trianglePaint.setAntiAlias(true);
drawPaint.setColor(Color.BLACK);
drawPaint.setTypeface(Typeface.create(Typeface.DEFAULT, Typeface.BOLD));
drawPaint.setShadowLayer(1f, 0f, 1f, Color.BLACK);
}
// Constractors ...
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (bitmap != null) {
Bitmap tempBitmap = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.RGB_565);
Canvas tempCanvas = new Canvas(tempBitmap);
tempCanvas.drawBitmap(bitmap, 0, 0, null);
Path path = new Path();
path.setFillType(Path.FillType.EVEN_ODD);
float size = bitmap.getWidth() * DISCOUNT_SIDE_SIZE;
path.lineTo(size, 0);
path.lineTo(0, size);
path.lineTo(0, 0);
path.close();
tempCanvas.drawPath(path, trianglePaint);
float scale = getResources().getDisplayMetrics().density;
drawPaint.setTextSize((int) (14 * scale));
Rect textBounds = new Rect();
drawPaint.getTextBounds("50%", 0, "50%".length(), textBounds);
int x = (int) (size / 2) - textBounds.width() / 2;
int y = (int) (size / 2) - textBounds.height() / 2;
tempCanvas.save();
tempCanvas.rotate(-45, x, y);
tempCanvas.drawText("50%", x, y, drawPaint);
tempCanvas.restore();
setImageDrawable(new BitmapDrawable(getContext().getResources(), tempBitmap));
}
}
#Override
public void setImageBitmap(Bitmap bitmap) {
this.bitmap = bitmap;
invalidate();
}
}
what can I do to solve this problem ?
You can try something like this
1) Measure the width of your text
Use measureText
2) From the point you are drawing calculate the width remaining to draw
3) Now depending on the use case you can curtail the length of text or scale the text as needed
int textWidthRequired = (int) drawPaint.measureText(textToDraw);
int widthRemainingToDraw = totalWidth/2 - textDrawX;
if(textWidthRequired > widthRemainingToDraw){
//handling
}
// draw text
tempCanvas.drawText(textToDraw,textDrawX, textDrawY, drawPaint);
Depending on how high up you want the text to be, you can use properties of similar triangles to first determine the maximum width of the text. In your case, size = the triangle's base, and size = the triangle's height/altitude. Let's define two variables:
Correction: The altitude won't be equal to the base. You'd need to calculate the altitude in order to use the below solution.
float triangleBase = size; // triangle base
float triangleAltitude = size; // Calculate this.
Let's say we want the text to be halfway up the center of the triangle:
float textYHeight = triangleHeight/2;
We figure out the width of the triangle at this point by using the following formula since the sides of similar triangles are proportional:
baseOfTriangleA/baseOfTriangleB = altitudeOfTriangleA/altitudeOfTriangleB;
float triangleWidthAtTextYLocation = (textYHeight * triangleBase)/triangleAltitude;
Now that we know what the width of the triangle is at this location, we can just iterate through different text scales until the text width is less than the value triangleWidthAtTextYlocation.
float scale = getResources().getDisplayMetrics().density;
int scaleFactor = 0;
drawPaint.setTextSize((int) (scaleFactor * scale));
Rect textBounds = new Rect();
drawPaint.getTextBounds("50%", 0, "50%".length(), textBounds);
while(textBounds.length < triangleWidthAtTextYLocation){
// Re-measure the text until it exceeds the width
scaleFactor++;
drawPaint.setTextSize((int) (scaleFactor * scale));
drawPaint.getTextBounds("50%", 0, "50%".length(), textBounds);
}
// Once we know the scaleFactor that puts it over the width of the triangle
// at that location, we reduce it by 1 to be just under that width:
scaleFactor = Maths.abs(scaleFactor - 1);
// final text size:
drawPaint.setTextSize((int) (scaleFactor * scale));

How to create a partially-rounded-corners-rectangular drawable with center-crop and without creating new bitmap?

Background
I've already seen how to create a drawable that's circular out of a bitmap, and also how to add an outline (AKA stroke) around it, here.
The problem
I can't find out how to do a similar task for rounding only some of the corners of the bitmap, inside the drawable, without creating a new bitmap, and still do it for a center-crop ImageView.
What I've found
This is what I've found, but it does create a new bitmap, and when using it in an imageView with center-crop (source here):
/**
* Create rounded corner bitmap from original bitmap.
*
* #param input Original bitmap.
* #param cornerRadius Corner radius in pixel.
* #param squareTL,squareTR,squareBL,squareBR where to use square corners instead of rounded ones.
*/
public static Bitmap getRoundedCornerBitmap(final Bitmap input, final float cornerRadius, final int w, final int h,
final boolean squareTL, final boolean squareTR, final boolean squareBL, final boolean squareBR) {
final Bitmap output = Bitmap.createBitmap(w, h, Config.ARGB_8888);
final Canvas canvas = new Canvas(output);
final int color = 0xff424242;
final Rect rect = new Rect(0, 0, w, h);
final RectF rectF = new RectF(rect);
// make sure that our rounded corner is scaled appropriately
Paint paint = new Paint();
paint.setXfermode(null);
paint.setAntiAlias(true);
canvas.drawARGB(0, 0, 0, 0);
paint.setColor(color);
canvas.drawRoundRect(rectF, cornerRadius, cornerRadius, paint);
// draw rectangles over the corners we want to be square
if (squareTL)
canvas.drawRect(0, 0, w / 2, h / 2, paint);
if (squareTR)
canvas.drawRect(w / 2, 0, w, h / 2, paint);
if (squareBL)
canvas.drawRect(0, h / 2, w / 2, h, paint);
if (squareBR)
canvas.drawRect(w / 2, h / 2, w, h, paint);
paint.setXfermode(PORTER_DUFF_XFERMODE_SRC_IN);
canvas.drawBitmap(input, 0, 0, paint);
return output;
}
And, this is what I've found for creating a rounded corners drawable that acts on all corners:
public static class RoundedCornersDrawable extends Drawable {
private final float mCornerRadius;
private final RectF mRect = new RectF();
private final BitmapShader mBitmapShader;
private final Paint mPaint;
public RoundedCornersDrawable(final Bitmap bitmap, final float cornerRadius) {
mCornerRadius = cornerRadius;
mBitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP,
Shader.TileMode.CLAMP);
mPaint = new Paint();
mPaint.setAntiAlias(false);
mPaint.setShader(mBitmapShader);
mRect.set(0, 0, bitmap.getWidth(), bitmap.getHeight());
}
#Override
protected void onBoundsChange(final Rect bounds) {
super.onBoundsChange(bounds);
mRect.set(0, 0, bounds.width(), bounds.height());
}
#Override
public void draw(final Canvas canvas) {
canvas.drawRoundRect(mRect, mCornerRadius, mCornerRadius, mPaint);
}
#Override
public int getOpacity() {
return PixelFormat.TRANSLUCENT;
}
#Override
public void setAlpha(final int alpha) {
mPaint.setAlpha(alpha);
}
#Override
public void setColorFilter(final ColorFilter cf) {
mPaint.setColorFilter(cf);
}
}
But this solution only works well if the imageView shows the content while maintaining the same aspect ratio as the bitmap, and also has its size pre-determined.
The question
How to create a center-cropped drawable, that shows a bitmap, has rounded corners for specific corners, and also be able to show an outline/stroke around it?
I want to do it without creating a new bitmap or extending ImageView. Only use a drawable that has the bitmap as the input.
The SMART way is to use the PorterDuff blending mode. It's really simple and slick to create any fancy shading, blending, "crop" effect. you can find a lot of good tutorial about PorterDuff. here a good one.
I always use this library to achieve what you are looking for. you can round any corner you want and also add stroke.
https://github.com/vinc3m1/RoundedImageView
You can use it or see it's source codes just for inspiration.
EDIT
there is no need to use Image View and make bitmap or drawable yourself and show it in Image View.
Just replace Image View with Rounded Image View and it will handle everything for you without any extra work in code !
here is sample :
<com.makeramen.roundedimageview.RoundedImageView
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/imageView1"
android:scaleType="centerCrop"
app:riv_corner_radius="8dp"
app:riv_border_width="2dp"
app:riv_border_color="#333333"
app:riv_oval="false" />
In code, just pass any image resource to it or use any Image Loader with it.
RoundedImageView myRoundedImage=(RoundedImageView)findViewById(R.id.imageView1);
myRoundedImage.setImageResource(R.drawable.MY_DRAWABLE);
// OR
ImageLoader.getInstance().displayImage(YOUR_IMAGE_URL, myRoundedImage);
if you want to just make specific corners rounded try this:
<com.makeramen.roundedimageview.RoundedImageView
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/imageView1"
android:scaleType="centerCrop"
app:riv_corner_radius_top_right="8dp"
app:riv_corner_radius_bottom_right="8dp"
app:riv_border_width="2dp"
app:riv_border_color="#333333"
app:riv_oval="false" />
Well, you can create a new .xml drawable named my_background and paste this code below:
<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle"
>
<solid android:color="#00000000"/>
<corners
android:bottomLeftRadius="12dp"
android:bottomRightRadius="12dp"
android:topLeftRadius="12dp"
android:topRightRadius="12dp" />
<stroke
android:width="1dp"
android:color="#000000"
/>
</shape>
Then, you set your ImageButton's, ImageView's background to your new drawable, like this:
android:background="#drawable/my_background"
android:scaleType="centerCrop"
or programatically:
myView.setBackground(R.drawable.my_background);
Hope it helps!
EDIT:
To programmatically create a similar drawable, you can use it:
GradientDrawable shape = new GradientDrawable();
shape.setShape(GradientDrawable.RECTANGLE);
shape.setCornerRadii(new float[] { 8, 8, 8, 8, 0, 0, 0, 0 });
shape.setColor(Color.TRANSPARENT);
shape.setStroke(3, Color.BLACK);
v.setBackgroundDrawable(shape);
Ok, here's my try. The only gotcha is that "int corners" is meant to be a set of flags. Such as 0b1111 where each 1 represents a corner to be rounded, and 0 is the opposite. The order is TOP_LEFT, TOP_RIGHT, BOTTOM_LEFT, BOTTOM_RIGHT.
example usage first, formatted for readability:
((ImageView) findViewById(R.id.imageView)).setImageDrawable(
new RoundedRectDrawable(
getResources(),
bitmap,
(float) .15,
0b1101,
8,
Color.YELLOW
)
);
code:
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.drawable.BitmapDrawable;
import android.os.SystemClock;
/**
* Created by mliu on 4/15/16.
*/
public class RoundedRectDrawable extends BitmapDrawable {
private final BitmapShader bitmapShader;
private final Paint p;
private final RectF rect;
private final float borderRadius;
private final float outlineBorderRadius;
private final int w;
private final int h;
private final int corners;
private final int border;
private final int bordercolor;
public RoundedRectDrawable(final Resources resources, final Bitmap bitmap, float borderRadiusSeed, int corners, int borderPX, int borderColor) {
super(resources, bitmap);
bitmapShader = new BitmapShader(getBitmap(),
BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP);
final Bitmap b = getBitmap();
p = getPaint();
p.setAntiAlias(true);
p.setShader(bitmapShader);
w = b.getWidth();
h = b.getHeight();
rect = new RectF(0,0,w,h);
borderRadius = borderRadiusSeed * Math.min(w, h);
border = borderPX;
this.corners = corners;
this.bordercolor = borderColor;
outlineBorderRadius = borderRadiusSeed * Math.min(w+border,h+border);
}
#Override
public void draw(final Canvas canvas) {
if ((corners&0b1111)==0){
if (border>0) {
Paint border = new Paint();
border.setColor(bordercolor);
canvas.drawRect(rect, border);
}
canvas.drawRect(rect.left + border, rect.top + border, rect.width() - border, rect.height() - border, p);
} else {
if (border >0) {
Paint border = new Paint();
border.setColor(bordercolor);
canvas.drawRoundRect(rect, outlineBorderRadius, outlineBorderRadius, border);
if ((corners & 0b1000) == 0) {
//top left
canvas.drawRect(rect.left, rect.top, rect.width() / 2, rect.height() / 2, border);
}
if ((corners & 0b0100) == 0) {
//top right
canvas.drawRect(rect.width() / 2, rect.top, rect.width(), rect.height() / 2, border);
}
if ((corners & 0b0010) == 0) {
//bottom left
canvas.drawRect(rect.left, rect.height() / 2, rect.width() / 2, rect.height(), border);
}
if ((corners & 0b0001) == 0) {
//bottom right
canvas.drawRect(rect.width() / 2, rect.height() / 2, rect.width(), rect.height(), border);
}
}
canvas.drawRoundRect(new RectF(rect.left + border, rect.top + border, rect.width() - border, rect.height() - border), borderRadius, borderRadius, p);
if ((corners & 0b1000) == 0) {
//top left
canvas.drawRect(rect.left + border, rect.top + border, rect.width() / 2, rect.height() / 2, p);
}
if ((corners & 0b0100) == 0) {
//top right
canvas.drawRect(rect.width() / 2, rect.top + border, rect.width() - border, rect.height() / 2, p);
}
if ((corners & 0b0010) == 0) {
//bottom left
canvas.drawRect(rect.left + border, rect.height() / 2, rect.width() / 2, rect.height() - border, p);
}
if ((corners & 0b0001) == 0) {
//bottom right
canvas.drawRect(rect.width() / 2, rect.height() / 2, rect.width() - border, rect.height() - border, p);
}
}
}
}
So, this handles the outline first, if needed, then the bitmap. It marks the canvas up with a rounded rect first, then "squares out" each corner you don't want to round. Seems highly inefficient, and probably is, but average case run time before minimal optimizations (corners = 0b0000, 10 canvas.draw calls) takes ~ 200us on a S7. And, that time is SUPER inconsistent based on phone usage. I've gotten as low as 80us and as high as 1.5ms.
NOTES/WARNING: I am BAD at this. This is not optimal. There's probably better answers already here on SO. The subject matter is just a bit uncommon and difficult to search up. I was originally not going to post this, but at time of writing this is still not marked answered, and the library OP did not wish to use due to problems with their Drawable actually use a very similar approach as my terrible solution. So, now I'm less embarrassed to share this. Additionally, though what I posted today was 95% written yesterday, I know I got some of this code from a tutorial or a SO post, but I can't remember who to attribute cause I didn't end up using it in my project. Apologies whoever you are.

How to draw Arc between two points on the Canvas?

I have two points in the canvas, now I'm able to draw a line between those points like this below image by using
This code canvas.drawLine(p1.x, p1.y, p2.x, p2.y, paint);
I want to draw the arc between two points like below image.
How can I draw like this.
Finally I got the solution from this code:
float radius = 20;
final RectF oval = new RectF();
oval.set(point1.x - radius, point1.y - radius, point1.x + radius, point1.y+ radius);
Path myPath = new Path();
myPath.arcTo(oval, startAngle, -(float) sweepAngle, true);
To calculate startAngle, use this code:
int startAngle = (int) (180 / Math.PI * Math.atan2(point.y - point1.y, point.x - point1.x));
Here, point1 means where you want to start drawing the Arc. sweepAngle means the angle between two lines. We have to calculate that by using two points like the blue points in my Question image.
Do something like this:
//Initialized paint on a class level object.
Paint p = new Paint();
p.setColor(Color.BLACK);
//Calculate the rect / bounds of oval
RectF rectF = new RectF(50, 20, 100, 80);
#Override
protected void onDraw(Canvas canvas) {
//Do the drawing in onDraw() method of View.
canvas.drawArc (rectF, 90, 45, false, p);
}
first we need to visual how the coordinates are in terms of start and sweep angels then it will become more clear.
so if you wanted just the right top piece of the circle, we could do something like this:
val rect = RectF(0f, 0f, 500f, 300f)
val paint = Paint()
paint.apply {
strokeWidth = 5f
setStyle(Paint.Style.STROKE)
color = COLOR.BLUE
}
path.addArc(rect, 270f, 90f)
..
this starts at 270 (per the diagram above and 'sweeps` 90 degrees forward. you then have this shape:
let's create one more so you get the hang of it. this time let's use a negative value: we want to create a semi half moon (arc) starting from the right side:
path.addArc(rect, 0f, -180f)
here we started at 0 and 'sweeped` -180 degrees.
and the results are:
I was trying to do something a little different and it's all about calculating sweep and start angles.
I wanted to show an arc that represents progress on a circle that goes from top to bottom.
So I had progress value from 0...100 and I want to show an arc that start from top to bottom to fill the circle when the progress is 100.
To calculate the sweepAngle I use:
int sweepAngle = (int) (360 * (getProgress() / 100.f));
Next is to calculate the startAngle
int startAngle = 270 - sweepAngle / 2;
Start Angle is calculated this way because:
It's always going to start from the left side, starting from the top to bottom. So starting angle at the top equals 270 (Note that it goes clockwise and 0 = 3 o'clock, so 12 o'clock equals 270 degrees)
Next I want to calculate how far I'm going to get away from my starting point (270) and to do that I only calculate half of the sweep angle because only half of the arc will be on the left side and the other half on the right side.
So considering I have progress of 25%
sweepAngle = 90 degrees (90 degrees is quarter of a circle)
start angle = 225 (45 degrees away from 270)
If you want the progress to go from other sides (Left to right, right to left etc..) you will only need to replace 270 with the starting the angle.
I may be late to answer but I got more information.
After Android Lollipop there are two ways to address this problem
public void drawArc(RectF oval, float startAngle, float sweepAngle,
boolean useCenter, Paint paint)
public void drawArc(float left, float top, float right, float bottom,
float startAngle, float sweepAngle, boolean useCenter, Paint paint)
Usage:
RectF rectF = new RectF(left, top, right, bottom);
// method 1
canvas.drawArc (rectF, 90, 45, true, paints[0]);
// method 2
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
canvas.drawArc (left, top, right, bottom, 0, 45, true, paints[1]);
}
Sweep angle is nothing more than angle of Sector which is drawn clockwise eg. for below code
private void drawArcs(Canvas canvas) {
RectF rectF = new RectF(left, top, right, bottom);
// white arc
canvas.drawArc (rectF, 90, 45, true, paints[0]);
// Green arc
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
canvas.drawArc (left, top, right, bottom, 0, 45, true, paints[1]);
}
// Red stroked arc
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
canvas.drawArc (left, top, right, bottom, 180, 45, true, paints[2]);
}
}
Result will look like this
Same can be achieved with the help of defining Paths and then iterating over them in onDraw method as illustrated in this snippet:
public class ArcDrawable extends Drawable {
private int left, right, top, bottom;
private Paint[] paints = new Paint[3];
private HashMap<Path, Paint> pathMap = new HashMap();
public ArcDrawable() {
// white paint
Paint whitePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
whitePaint.setColor(Color.WHITE);
paints[0]= whitePaint;
// green paint
Paint greenPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
greenPaint.setColor(Color.GREEN);
paints[1]= greenPaint;
// red paint
Paint redPaint =new Paint(Paint.ANTI_ALIAS_FLAG);
redPaint.setColor(Color.RED);
redPaint.setStyle(Paint.Style.STROKE);
paints[2]= redPaint;
}
#Override
public void draw(Canvas canvas) {
//----------USE PATHS----------
// Define and use custom Path
for (Map.Entry<Path, Paint> entry : pathMap.entrySet()) {
// Draw Path on respective Paint style
canvas.drawPath(entry.getKey(), entry.getValue());
}
// -------OR use conventional Style---------
//drawArcs(canvas);
}
//Same result
private void drawArcs(Canvas canvas) {
RectF rectF = new RectF(left, top, right, bottom);
// method 1
canvas.drawArc (rectF, 90, 45, true, paints[0]);
// method 2
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
canvas.drawArc (left, top, right, bottom, 0, 45, true, paints[1]);
}
// method two with stroke
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
canvas.drawArc (left, top, right, bottom, 180, 45, true, paints[2]);
}
}
#Override
protected void onBoundsChange(Rect bounds) {
super.onBoundsChange(bounds);
int width = bounds.width();
int height = bounds.height();
left = bounds.left;
right = bounds.right;
top = bounds.top;
bottom = bounds.bottom;
final int size = Math.min(width, height);
final int centerX = bounds.left + (width / 2);
final int centerY = bounds.top + (height / 2);
pathMap.clear();
//update pathmap using new bounds
recreatePathMap(size, centerX, centerY);
invalidateSelf();
}
private Path recreatePathMap(int size, int centerX, int centerY) {
RectF rectF = new RectF(left, top, right, bottom);
// first arc
Path arcPath = new Path();
arcPath.moveTo(centerX,centerY);
arcPath.arcTo (rectF, 90, 45);
arcPath.close();
// add to draw Map
pathMap.put(arcPath, paints[0]);
//second arc
arcPath = new Path();
arcPath.moveTo(centerX,centerY);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
arcPath.arcTo (rectF, 0, 45);
}
arcPath.close();
// add to draw Map
pathMap.put(arcPath, paints[1]);
// third arc
arcPath = new Path();
arcPath.moveTo(centerX,centerY);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
arcPath.arcTo (rectF, 180, 45);
}
arcPath.close();
// add to draw Map
pathMap.put(arcPath, paints[2]);
return arcPath;
}
#Override
public void setAlpha(int alpha) {
}
#Override
public void setColorFilter(#Nullable ColorFilter colorFilter) {
}
#Override
public int getOpacity() {
return 0;
}
}
Complete source code:
https://github.com/hiteshsahu/Arc-Drawable
a sample for draw arc.
public static Bitmap clipRoundedCorner(Bitmap bitmap, float r, boolean tr, boolean tl, boolean bl, boolean br)
{
int W = bitmap.getWidth();
int H = bitmap.getHeight();
if (r < 0)
r = 0;
int smallLeg = W;
if(H < W )
smallLeg = H;
if (r > smallLeg)
r = smallLeg / 2;
float lineStop = r/2;
Path path = new Path();
path.moveTo(0,0);
if(tr)
{
path.moveTo(0, lineStop);
path.arcTo(new RectF(0,0, r,r), 180, 90, false);
}
path.lineTo(W-lineStop, 0);
if(tl)
path.arcTo(new RectF(W-r,0, W,r), 270, 90, false);
else
path.lineTo(W, 0);
path.lineTo(W, H-lineStop);
if(bl)
path.arcTo(new RectF(W-r,H-r, W,H), 0, 90, false);
else
path.lineTo(W, H);
path.lineTo(lineStop, H);
if(br)
path.arcTo(new RectF(0,H-r, r,H), 90, 90, false);
else
path.lineTo(0,H);
if(tr)
path.lineTo(0,lineStop);
else
path.lineTo(0,0);
Bitmap output = Bitmap.createBitmap(W, H, Config.ARGB_8888);
Canvas canvas = new Canvas(output);
final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(Color.BLACK);
canvas.drawPath(path, paint);
paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
canvas.drawBitmap(bitmap, 0, 0, paint);
return output;
}
A simple solution was suggested here by Langkiller. This draws a cubic line from the start point via the control point to the end point.
Path path = new Path();
float startX = 0;
float startY = 2;
float controlX = 2;
float controlY = 4;
float endX = 4
float endY = 2
conePath.cubicTo(startX, startY, controlX, controlY,endX, endY);
Paint paint = new Paint();
paint.setARGB(200, 62, 90, 177);
paint.setStyle(Paint.Style.FILL);
canvas.drawPath(path, paint)

How to use android canvas to draw a Rectangle with only topleft and topright corners round?

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);
For API 21 and above the Path class added a new method addRoundRect() which you can use it like this.
corners = new float[]{
80, 80, // Top left radius in px
80, 80, // Top right radius in px
0, 0, // Bottom right radius in px
0, 0 // Bottom left radius in px
};
final Path path = new Path();
path.addRoundRect(rect, corners, Path.Direction.CW);
canvas.drawPath(path, mPaint);
in Kotlin
val corners = floatArrayOf(
80f, 80f, // Top left radius in px
80f, 80f, // Top right radius in px
0f, 0f, // Bottom right radius in px
0f, 0f // Bottom left radius in px
)
val path = Path()
path.addRoundRect(rect, corners, Path.Direction.CW)
canvas.drawPath(path, mPaint)
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.
I would draw two rectangles:
canvas.drawRect(new RectF(0, 110, 100, 290), paint);
canvas.drawRoundRect(new RectF(0, 100, 100, 200), 6, 6, paint);
Or something like that, you just overlap them so that the upper corners will be round. Preferably you should write a method for this
I changed this answer so you can set which corner you want to be round and which one you want to be sharp. also works on pre-lolipop
Usage Example:
only top-right and botton-right corners are rounded
Path path = RoundedRect(0, 0, fwidth , fheight , 5,5,
false, true, true, false);
canvas.drawPath(path,myPaint);
RoundRect:
public static Path RoundedRect(
float left, float top, float right, float bottom, float rx, float ry,
boolean tl, boolean tr, boolean br, boolean bl
){
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);
if (tr)
path.rQuadTo(0, -ry, -rx, -ry);//top-right corner
else{
path.rLineTo(0, -ry);
path.rLineTo(-rx,0);
}
path.rLineTo(-widthMinusCorners, 0);
if (tl)
path.rQuadTo(-rx, 0, -rx, ry); //top-left corner
else{
path.rLineTo(-rx, 0);
path.rLineTo(0,ry);
}
path.rLineTo(0, heightMinusCorners);
if (bl)
path.rQuadTo(0, ry, rx, ry);//bottom-left corner
else{
path.rLineTo(0, ry);
path.rLineTo(rx,0);
}
path.rLineTo(widthMinusCorners, 0);
if (br)
path.rQuadTo(rx, 0, rx, -ry); //bottom-right corner
else{
path.rLineTo(rx,0);
path.rLineTo(0, -ry);
}
path.rLineTo(0, -heightMinusCorners);
path.close();//Given close, last lineto can be removed.
return path;
}
you can easily achieve this by using Path:
val radiusArr = floatArrayOf(
15f, 15f,
15f, 15f,
0f, 0f,
0f, 0f
)
val myPath = Path()
myPath.addRoundRect(
RectF(0f, 0f, 400f, 400f),
radiusArr,
Path.Direction.CW
)
canvas.drawPath(myPath, paint)
Simple helper function written in Kotlin.
private fun Canvas.drawTopRoundRect(rect: RectF, paint: Paint, radius: Float) {
// Step 1. Draw rect with rounded corners.
drawRoundRect(rect, radius, radius, paint)
// Step 2. Draw simple rect with reduced height,
// so it wont cover top rounded corners.
drawRect(
rect.left,
rect.top + radius,
rect.right,
rect.bottom,
paint
)
}
Usage:
canvas.drawTopRoundRect(rect, paint, radius)
public static Path composeRoundedRectPath(RectF rect, float topLeftDiameter, float topRightDiameter,float bottomRightDiameter, float bottomLeftDiameter){
Path path = new Path();
topLeftDiameter = topLeftDiameter < 0 ? 0 : topLeftDiameter;
topRightDiameter = topRightDiameter < 0 ? 0 : topRightDiameter;
bottomLeftDiameter = bottomLeftDiameter < 0 ? 0 : bottomLeftDiameter;
bottomRightDiameter = bottomRightDiameter < 0 ? 0 : bottomRightDiameter;
path.moveTo(rect.left + topLeftDiameter/2 ,rect.top);
path.lineTo(rect.right - topRightDiameter/2,rect.top);
path.quadTo(rect.right, rect.top, rect.right, rect.top + topRightDiameter/2);
path.lineTo(rect.right ,rect.bottom - bottomRightDiameter/2);
path.quadTo(rect.right ,rect.bottom, rect.right - bottomRightDiameter/2, rect.bottom);
path.lineTo(rect.left + bottomLeftDiameter/2,rect.bottom);
path.quadTo(rect.left,rect.bottom,rect.left, rect.bottom - bottomLeftDiameter/2);
path.lineTo(rect.left,rect.top + topLeftDiameter/2);
path.quadTo(rect.left,rect.top, rect.left + topLeftDiameter/2, rect.top);
path.close();
return path;
}
I achieved this by following the below steps.
These are the pre-requisites for the rounded rectangle to look neat
The radius of the edges have to be equal to the (height of the rectangle / 2). This is because if its any different value then the place where the curve meets straight line of the rectangle will not be
Next is the steps to draw the rounded rectangle.
First we draw 2 circles on the left and right side, with the radius = height of rectange / 2
Then we draw a rectangle between these circles to get the desired rounded rectangle.
I am posting the code below
private void drawRoundedRect(Canvas canvas, float left, float top, float right, float bottom) {
float radius = getHeight() / 2;
canvas.drawCircle(radius, radius, radius, mainPaint);
canvas.drawCircle(right - radius, radius, radius, mainPaint);
canvas.drawRect(left + radius, top, right - radius, bottom, mainPaint);
}
Now this results in a really nice rounded rectangle like the one shown below
This is an old question, however I wanted to add my solution because it uses the native SDK without lots of custom code or hacky drawing. This solution is supported back to API 1.
The way to do this properly is to create a path (as mentioned in other answers) however the previous answers seem to overlook the addRoundedRect function call that takes radii for each corner.
Variables
private val path = Path()
private val paint = Paint()
Setup Paint
paint.color = Color.RED
paint.style = Paint.Style.FILL
Update Path with Size Changes
Call this somewhere that isn't onDraw, such as onMeasure for a view or onBoundChange for a drawable. If it doesn't change (like this example) you could put this code where you set up your paint.
val radii = floatArrayOf(
25f, 25f, //Top left corner
25f, 25f, //Top right corner
0f, 0f, //Bottom right corner
0f, 0f, //Bottom left corner
)
path.reset() //Clears the previously set path
path.addRoundedRect(0f, 0f, 100f, 100f, radii, Path.Direction.CW)
This code creates a 100x100 rounded rect with the top corners rounded with a 25 radius.
Draw Path
Call this in onDraw for a view or draw for a drawable.
canvas.drawPath(path, paint)
A Path#arcTo() version to draw the rounded side if the radius is half of the height.
fun getPathOfRoundedRectF(
rect: RectF,
topLeftRadius: Float = 0f,
topRightRadius: Float = 0f,
bottomRightRadius: Float = 0f,
bottomLeftRadius: Float = 0f
): Path {
val tlRadius = topLeftRadius.coerceAtLeast(0f)
val trRadius = topRightRadius.coerceAtLeast(0f)
val brRadius = bottomRightRadius.coerceAtLeast(0f)
val blRadius = bottomLeftRadius.coerceAtLeast(0f)
with(Path()) {
moveTo(rect.left + tlRadius, rect.top)
//setup top border
lineTo(rect.right - trRadius, rect.top)
//setup top-right corner
arcTo(
RectF(
rect.right - trRadius * 2f,
rect.top,
rect.right,
rect.top + trRadius * 2f
), -90f, 90f
)
//setup right border
lineTo(rect.right, rect.bottom - trRadius)
//setup bottom-right corner
arcTo(
RectF(
rect.right - brRadius * 2f,
rect.bottom - brRadius * 2f,
rect.right,
rect.bottom
), 0f, 90f
)
//setup bottom border
lineTo(rect.left + blRadius, rect.bottom)
//setup bottom-left corner
arcTo(
RectF(
rect.left,
rect.bottom - blRadius * 2f,
rect.left + blRadius * 2f,
rect.bottom
), 90f, 90f
)
//setup left border
lineTo(rect.left, rect.top + tlRadius)
//setup top-left corner
arcTo(
RectF(
rect.left,
rect.top,
rect.left + tlRadius * 2f,
rect.top + tlRadius * 2f
),
180f,
90f
)
close()
return this
}
}
One simple and efficient way to draw a solid side is to use clipping - rect clipping is essentially free, and a lot less code to write than a custom Path.
If I want a 300x300 rect, with the top left and right rounded by 50 pixels, you can do:
canvas.save();
canvas.clipRect(0, 0, 300, 300);
canvas.drawRoundRect(new RectF(0, 0, 300, 350), 50, 50, paint);
canvas.restore();
This approach will only work for rounding on 2 or 3 adjacent corners, so it's a little less configurable than a Path based approach, but using round rects is more efficient, since drawRoundRect() is fully hardware accelerated (that is, tessellated into triangles) while drawPath() always falls back to software rendering (software-draw a path bitmap, and upload that to be cached on the GPU).
Not a huge performance issue for small infrequent drawing, but if you're animating paths, the cost of software draw can make your frame times longer, and increase your chance to drop frames. The path mask also costs memory.
If you do want to go with a Path-based approach, I'd recommend using GradientDrawable to simplify the lines of code (assuming you don't need to set a custom shader, e.g. to draw a Bitmap).
mGradient.setBounds(0, 0, 300, 300);
mGradient.setCornerRadii(new int[] {50,50, 50,50, 0,0, 0,0});
With GradientDrawable#setCornerRadii(), you can set any corner to be any roundedness, and reasonably animate between states.
Here is my answer to the above question. Here, I have created Kotlin extension function which uses Path along with the quadTo function which can be used in lower-level APIs also.
fun Canvas.drawRoundRectPath(
rectF: RectF,
radius: Float,
roundTopLeft: Boolean,
roundTopRight: Boolean,
roundBottomLeft: Boolean,
roundBottomRight: Boolean,
paint: Paint) {
val path = Path()
//Move path cursor to start point
if (roundBottomLeft) {
path.moveTo(rectF.left, rectF.bottom - radius)
} else {
path.moveTo(rectF.left, rectF.bottom)
}
// drawing line and rounding top left curve
if (roundTopLeft) {
path.lineTo(rectF.left, rectF.top + radius)
path.quadTo(rectF.left, rectF.top, rectF.left + radius, rectF.top)
} else {
path.lineTo(rectF.left, rectF.top)
}
// drawing line an rounding top right curve
if (roundTopRight) {
path.lineTo(rectF.right - radius, rectF.top)
path.quadTo(rectF.right, rectF.top, rectF.right, rectF.top + radius)
} else {
path.lineTo(rectF.right, rectF.top)
}
// drawing line an rounding bottom right curve
if (roundBottomRight) {
path.lineTo(rectF.right, rectF.bottom - radius)
path.quadTo(rectF.right, rectF.bottom, rectF.right - radius, rectF.bottom)
} else {
path.lineTo(rectF.right, rectF.bottom)
}
// drawing line an rounding bottom left curve
if (roundBottomLeft) {
path.lineTo(rectF.left + radius, rectF.bottom)
path.quadTo(rectF.left, rectF.bottom, rectF.left, rectF.bottom - radius)
} else {
path.lineTo(rectF.left, rectF.bottom)
}
path.close()
drawPath(path, paint)
}
We can call the function with canvas object and pass the RectF with the dimension on which we want to apply the curve.
Also, we can pass the boolean for the corners which we want to round.
This answer can further be customized to accept radius for individual corners.
You can draw that piece by piece using drawLine() and drawArc() functions from the Canvas.
Maybe the following code can help you
Paint p = new Paint();
p.setColor(color);
float[] corners = new float[]{
15, 15, // Top, left in px
15, 15, // Top, right in px
15, 15, // Bottom, right in px
15, 15 // Bottom,left in px
};
final Path path = new Path();
path.addRoundRect(rect, corners, Path.Direction.CW);
// Draw
canvas.drawPath(path, p);
Use PaintDrawable could be better:
val topLeftRadius = 10
val topRightRadius = 10
val bottomLeftRadius = 0
val bottomRightRadius = 0
val rect = Rect(0, 0, 100, 100)
val paintDrawable = PaintDrawable(Color.RED)
val outter = floatArrayOf(topLeftRadius, topLeftRadius, topRightRadius, topRightRadius,
bottomLeftRadius, bottomLeftRadius, bottomRightRadius, bottomRightRadius)
paintDrawable.setCornerRadii(outter)
paintDrawable.bounds = rect
paintDrawable.draw(canvas)
draw round rect with left rounded corners
private void drawRoundRect(float left, float top, float right, float bottom, Paint paint, Canvas canvas) {
Path path = new Path();
path.moveTo(left, top);
path.lineTo(right, top);
path.lineTo(right, bottom);
path.lineTo(left + radius, bottom);
path.quadTo(left, bottom, left, bottom - radius);
path.lineTo(left, top + radius);
path.quadTo(left, top, left + radius, top);
canvas.drawPath(path, onlinePaint);
}

Categories

Resources