How to use android canvas to draw a Rectangle with only topleft and topright corners round?
You can draw that piece by piece using drawLine()
and drawArc()
functions from the Canvas
.
How to draw a path with rounded corners
Canvas
has some pre-defined methods for drawing common shapes like circle and rectangle. In your scenario, you can use drawRoundRect
which needs a RectF
to draw a rectangle.
Here is an example:
class RoundedRect @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {
private val roundCorner = 32f
private val paint = Paint().apply {
color = Color.YELLOW
style = Paint.Style.FILL
isAntiAlias = true
}
private val strokePaint = Paint().apply {
color = Color.BLACK
strokeWidth = 4f
style = Paint.Style.STROKE
isAntiAlias = true
}
private var rect = RectF(0f, 0f, 0f, 0f)
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
super.onSizeChanged(w, h, oldw, oldh)
rect = RectF(0f, 0f, w.toFloat(), h.toFloat())
}
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
canvas.drawRoundRect(rect, roundCorner, roundCorner, paint)
canvas.drawRoundRect(rect, roundCorner, roundCorner, strokePaint)
}
}
BTW, If you want to draw rounded corners using a path, you must set pathEffect
with CornerPathEffect
.
Here is an example:
class RoundedRectUsingPath @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {
private val roundCorner = 32f
private val paint = Paint().apply {
color = Color.YELLOW
isAntiAlias = true
pathEffect = CornerPathEffect(roundCorner)
strokeCap = Paint.Cap.ROUND
}
private val strokePaint = Paint().apply {
color = Color.BLACK
strokeWidth = 4f
isAntiAlias = true
style = Paint.Style.STROKE
pathEffect = CornerPathEffect(roundCorner)
}
private var path = Path()
private val offset = 50f
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
super.onSizeChanged(w, h, oldw, oldh)
path = Path().apply {
moveTo(offset, offset)
lineTo(w.toFloat() - offset, offset)
lineTo(w.toFloat() - offset, h.toFloat() - offset)
lineTo(offset, h.toFloat() - offset)
}
path.close()
}
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
canvas.drawPath(path, paint)
canvas.drawPath(path, strokePaint)
}
}
How to draw a partial round rect on a android canvas?
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);
}
Draw round corners on top left top right bottom left bottom right using Path and RectF in Android
There is a Path#addRoundRect()
overload that takes a float
array of eight values wherein we can specify the x- and y-radius for each of the four corners. These values are in [x, y] pairs, starting at the top-left corner, and going clockwise around the rest. For those corners we want rounded, we set both values of the pair to the radius value, and leave them at zero for those we don't.
As an illustrative example, a simple method that will return a Path
that can be used in your snippet:
private Path getPath(float radius, boolean topLeft, boolean topRight,
boolean bottomRight, boolean bottomLeft) {
final Path path = new Path();
final float[] radii = new float[8];
if (topLeft) {
radii[0] = radius;
radii[1] = radius;
}
if (topRight) {
radii[2] = radius;
radii[3] = radius;
}
if (bottomRight) {
radii[4] = radius;
radii[5] = radius;
}
if (bottomLeft) {
radii[6] = radius;
radii[7] = radius;
}
path.addRoundRect(new RectF(0, 0, getWidth(), getHeight()),
radii, Path.Direction.CW);
return path;
}
Per your example description, rounding the top-left and top-right corners:
@Override
protected void onDraw(Canvas canvas) {
float radius = getContext().getResources().getDimension(R.dimen.round_corner_radius);
Path path = getPath(radius, true, true, false, false);
canvas.clipPath(path);
super.onDraw(canvas);
}
As always, I would recommend keeping the onDraw()
method as tight as possible, moving anything that doesn't absolutely have to be there elsewhere. The resource value for the radius, for instance, could be retrieved in the constructor, and kept in a field. Furthermore, the Path
could be constructed only when necessary; i.e., when the View
's size changes, or when the radius or chosen corners change.
Since I put together a simple custom ImageView
to test this, I'll include it here, as it demonstrates the above points. This custom View
also offers XML attributes that allow the corner radius and the rounded corners to be set in your layout.
public class RoundishImageView extends ImageView {
public static final int CORNER_NONE = 0;
public static final int CORNER_TOP_LEFT = 1;
public static final int CORNER_TOP_RIGHT = 2;
public static final int CORNER_BOTTOM_RIGHT = 4;
public static final int CORNER_BOTTOM_LEFT = 8;
public static final int CORNER_ALL = 15;
private static final int[] CORNERS = {CORNER_TOP_LEFT,
CORNER_TOP_RIGHT,
CORNER_BOTTOM_RIGHT,
CORNER_BOTTOM_LEFT};
private final Path path = new Path();
private int cornerRadius;
private int roundedCorners;
public RoundishImageView(Context context) {
this(context, null);
}
public RoundishImageView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public RoundishImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.RoundishImageView);
cornerRadius = a.getDimensionPixelSize(R.styleable.RoundishImageView_cornerRadius, 0);
roundedCorners = a.getInt(R.styleable.RoundishImageView_roundedCorners, CORNER_NONE);
a.recycle();
}
public void setCornerRadius(int radius) {
if (cornerRadius != radius) {
cornerRadius = radius;
setPath();
invalidate();
}
}
public int getCornerRadius() {
return cornerRadius;
}
public void setRoundedCorners(int corners) {
if (roundedCorners != corners) {
roundedCorners = corners;
setPath();
invalidate();
}
}
public boolean isCornerRounded(int corner) {
return (roundedCorners & corner) == corner;
}
@Override
protected void onDraw(Canvas canvas) {
if (!path.isEmpty()) {
canvas.clipPath(path);
}
super.onDraw(canvas);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
setPath();
}
private void setPath() {
path.rewind();
if (cornerRadius >= 1f && roundedCorners != CORNER_NONE) {
final float[] radii = new float[8];
for (int i = 0; i < 4; i++) {
if (isCornerRounded(CORNERS[i])) {
radii[2 * i] = cornerRadius;
radii[2 * i + 1] = cornerRadius;
}
}
path.addRoundRect(new RectF(0, 0, getWidth(), getHeight()),
radii, Path.Direction.CW);
}
}
}
For the XML attributes to work, the following needs to be in your <resources>
, which you can do by putting this file in your project's res/values/
folder, or adding to the one that might already be there.
attrs.xml
<resources>
<declare-styleable name="RoundishImageView">
<attr name="cornerRadius" format="dimension" />
<attr name="roundedCorners">
<flag name="topLeft" value="1" />
<flag name="topRight" value="2" />
<flag name="bottomRight" value="4" />
<flag name="bottomLeft" value="8" />
<flag name="all" value="15" />
</attr>
</declare-styleable>
</resources>
The cornerRadius
is a dimension attribute, and should be specified as a dp
or px
value. The roundedCorners
is a flag attribute, and multiple corners can be chosen using the pipe character, |
. For example:
<com.mycompany.myapp.RoundishImageView
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/riv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:scaleType="fitXY"
android:src="@drawable/magritte"
app:cornerRadius="@dimen/round_corner_radius"
app:roundedCorners="topLeft|topRight" />
How do i draw only corners of a rectangle in android canvas
Image
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint paint = new Paint(Paint.DITHER_FLAG);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(50);
paint.setColor(0xFF2287BB);
paint.setStrokeJoin(Paint.Join.MITER);
canvas.drawPath(createCornersPath(getWidth()/2 - 500, getHeight()/2 - 500, getWidth()/2 +500, getHeight()/2 + 500, 150), paint);
}
private Path createCornersPath(int left, int top, int right, int bottom, int cornerWidth){
Path path = new Path();
path.moveTo(left, top + cornerWidth);
path.lineTo(left, top);
path.lineTo(left + cornerWidth, top);
path.moveTo(right - cornerWidth, top);
path.lineTo(right, top);
path.lineTo(right , top + cornerWidth);
path.moveTo(left, bottom - cornerWidth);
path.lineTo(left, bottom);
path.lineTo(left + cornerWidth, bottom);
path.moveTo(right - cornerWidth, bottom);
path.lineTo(right, bottom);
path.lineTo(right, bottom - cornerWidth);
return path;
}
How to draw a rounded rectangle using HTML Canvas?
The HTML5 canvas doesn't provide a method to draw a rectangle with rounded corners.
How about using the lineTo()
and arc()
methods?
You can also use the quadraticCurveTo()
method instead of the arc()
method.
Related Topics
How to Listen for Preference Changes Within a Preferencefragment
Android - Apply Selectableitembackground in Xml with Support V7
How to Build a Native (Command Line) Executable to Run on Android
Android - Play Sound on Button Click - Null Pointer Exception
Error:Unexpected Lock Protocol Found in Lock File. Expected 3, Found 0
Extended Surfaceview's Ondraw() Method Never Called
Emulator Appearing Offline on M1 MAC After the Last Update of Arm64-V8A
Justify Text in an Android App Using a Webview But Presenting a Textview-Like Interface
How to Dynamically Query the Room Database at Runtime
How to Set the Output Image Use Com.Android.Camera.Action.Crop
Eclipse, Android, Scala Made Easy But Still Does Not Work
Adjust Layout When Soft Keyboard Is On
How to Iterate Through All Keys of Shared Preferences
How to Implement Uncaughtexception Android
Android: How to Get Gsm Signal Strength for All Available Network Operators