如何使用Android画布绘制矩形只有顶部和顶部的矩形圆?

我发现一个矩形的所有4个角落都是圆形的功能,但我想只有顶部2个角落。 我能做什么?

canvas.drawRoundRect(new RectF(0, 100, 100, 300), 6, 6, paint); 

您可以使用Canvas drawLine()drawArc()函数逐片绘制该片段。

我会画两个矩形:

 canvas.drawRect(new RectF(0, 110, 100, 290), paint); canvas.drawRoundRect(new RectF(0, 100, 100, 200), 6, 6, paint); 

或者类似的东西,你只是重叠他们,使上角将圆。 最好你应该为此写一个方法

使用路径。 它具有工作于API小于21的优点(Arc也因此受到限制,这就是为什么我是四)。 这是一个问题,因为不是每个人都有棒棒糖。 然而,你可以指定一个RectF,并用这个值设置值,并使用arc回到API 1,但是这样你就不会使用静态的(没有声明一个新对象来构建对象)。

绘制圆角矩形:

  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(); 

作为一个完整的功能:

 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; } 

你想要一直到那些角落,而不是四个角落。 这是设置trueToOriginalPost的确实。 只要在那里的控制点。

如果你想这样做,但不关心前棒棒糖的东西,并紧急坚持,如果你的rx和ry足够高,应该画一个圆圈。

 @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; } 

所以,conformToOriginalPost实际上绘制了一个圆角矩形,没有底部的两个圆角。

arcquadimage

我改变了这个答案,所以你可以设置你想要哪个角落,哪一个你想要尖锐。 也适用于pre-lolipop

用法示例

只有右上角和右下角是圆角的

  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; } 
 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; } 

用左圆角画出圆的矩形

  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); } 

简单的帮手功能写在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 ) } 

用法:

 canvas.drawTopRoundRect(rect, paint, radius) 

我按照以下步骤完成了这个任务。

这些是圆角矩形看起来整洁的先决条件

  • 边的半径必须等于(矩形的高度/ 2)。 这是因为如果它有任何不同的值,那么曲线与矩形的直线相交的地方将不会是

接下来是绘制圆角矩形的步骤。

  • 首先我们在左侧和右侧绘制2个圆,半径= rectange / 2的高度

  • 然后我们在这些圆圈之间绘制一个矩形以获得所需的圆角矩形。

我张贴下面的代码

 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); } 

现在这会产生一个非常好的圆角矩形,如下所示 在这里输入图像描述

一个简单而有效的方法来绘制一个坚实的一面是使用裁剪 – 剪裁本质上是免费的,并且比自定义的路径少写代码。

如果我想要一个300×300矩形,左上角和右下角50像素,你可以这样做:

 canvas.save(); canvas.clipRect(0, 0, 300, 300); canvas.drawRoundRect(new RectF(0, 0, 300, 350), 50, 50, paint); canvas.restore(); 

这种方法仅适用于2或3个相邻角上的四舍五入,所以与基于路径的方法相比,它的配置稍微少一些,但是使用圆角更有效,因为drawRoundRect()完全是硬件加速的(也就是镶嵌成三角形)而drawPath()总是回退到软件渲染(软件绘制一个路径位图,并上传到GPU缓存)。

对于小的不频繁绘图来说,这不是一个巨大的性能问题,但是如果你是动画路径,绘制软件的成本会使你的帧时间更长,并增加丢帧的机会。 路径掩码也花费内存。

如果你想要使用基于路径的方法,我建议使用GradientDrawable来简化代码行(假设你不需要设置自定义着色器,例如绘制一个位图)。

 mGradient.setBounds(0, 0, 300, 300); mGradient.setCornerRadii(new int[] {50,50, 50,50, 0,0, 0,0}); 

使用GradientDrawable#setCornerRadii() ,您可以将任何角落设置为任何圆角,并在各个状态之间进行合理的动画处理。