vir*_*sir 47 android draw android-canvas
我找到了一个矩形函数,所有四个角都是圆的,但我想只有前两个角.我能做什么?
canvas.drawRoundRect(new RectF(0, 100, 100, 300), 6, 6, paint);
Run Code Online (Sandbox Code Playgroud)
Tat*_*ize 51
使用路径.它具有为小于21的API工作的优点(因此,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();
Run Code Online (Sandbox Code Playgroud)
作为一个完整的功能:
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;
}
Run Code Online (Sandbox Code Playgroud)
你想要一直排到那些角落位,而不是四角形.这是conformToOriginalPost设置为true的内容.只需到那里的控制点.
如果你想这样做但不关心前Lollipop的东西,并且迫切地坚持如果你的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;
}
Run Code Online (Sandbox Code Playgroud)
因此,conformToOriginalPost实际绘制一个圆角矩形,而底部的两位没有圆角.
小智 43
我会画两个矩形:
canvas.drawRect(new RectF(0, 110, 100, 290), paint);
canvas.drawRoundRect(new RectF(0, 100, 100, 200), 6, 6, paint);
Run Code Online (Sandbox Code Playgroud)
或类似的东西,你只是重叠它们,以便上角是圆的.你最好为此写一个方法
Moh*_*abi 26
我改变了这个 答案,这样你就可以设置你想要圆的哪个角,以及你想要哪个角.也适用于pre-lolipop
用法示例:只有右上角和右下角是圆形的
Path path = RoundedRect(0, 0, fwidth , fheight , 5,5,
false, true, true, false);
canvas.drawPath(path,myPaint);
Run Code Online (Sandbox Code Playgroud)
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;
}
Run Code Online (Sandbox Code Playgroud)
Vad*_*rov 11
用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
)
}
Run Code Online (Sandbox Code Playgroud)
用法:
canvas.drawTopRoundRect(rect, paint, radius)
Run Code Online (Sandbox Code Playgroud)
对于API 21及更高版本,Path类添加了一个新方法addRoundRect(),您可以像这样使用它。
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);
Run Code Online (Sandbox Code Playgroud)
在科特林
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)
Run Code Online (Sandbox Code Playgroud)
小智 9
您可以使用 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)
Run Code Online (Sandbox Code Playgroud)
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;
}
Run Code Online (Sandbox Code Playgroud)
Path #arcTo()版本,用于在半径是高度的一半时绘制圆边。
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
}
}
Run Code Online (Sandbox Code Playgroud)
我通过以下步骤实现了这一目标。
这些是使圆角矩形看起来整洁的前提条件
接下来是绘制圆角矩形的步骤。
首先,我们在左侧和右侧绘制2个圆,半径=矩形的高度/ 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);
}
Run Code Online (Sandbox Code Playgroud)
绘制实体边的一种简单而有效的方法是使用裁剪——矩形裁剪本质上是免费的,并且比自定义路径要少得多的代码。
如果我想要一个 300x300 的矩形,左上角和右上角四舍五入 50 像素,你可以这样做:
canvas.save();
canvas.clipRect(0, 0, 300, 300);
canvas.drawRoundRect(new RectF(0, 0, 300, 350), 50, 50, paint);
canvas.restore();
Run Code Online (Sandbox Code Playgroud)
这种方法仅适用于 2 或 3 个相邻角的舍入,因此它比基于路径的方法可配置性稍差,但使用圆形矩形更有效,因为 drawRoundRect() 是完全硬件加速的(即镶嵌成三角形)而 drawPath() 总是回退到软件渲染(软件绘制路径位图,并将其上传到 GPU 上缓存)。
对于小幅不频繁的绘图来说,这不是一个巨大的性能问题,但如果您正在为路径设置动画,则软件绘图的成本可能会使您的帧时间更长,并增加丢帧的机会。路径掩码也会消耗内存。
如果您确实想使用基于路径的方法,我建议使用 GradientDrawable 来简化代码行(假设您不需要设置自定义着色器,例如绘制位图)。
mGradient.setBounds(0, 0, 300, 300);
mGradient.setCornerRadii(new int[] {50,50, 50,50, 0,0, 0,0});
Run Code Online (Sandbox Code Playgroud)
使用GradientDrawable#setCornerRadii(),您可以将任何角设置为任何圆角,并在状态之间合理地设置动画。
这是一个老问题,但是我想添加我的解决方案,因为它使用本机 SDK,没有大量自定义代码或 hacky 绘图。此解决方案支持回到 API 1。
正确执行此操作的方法是创建一条路径(如其他答案中所述),但是之前的答案似乎忽略了addRoundedRect为每个角取半径的函数调用。
变量
private val path = Path()
private val paint = Paint()
Run Code Online (Sandbox Code Playgroud)
设置油漆
paint.color = Color.RED
paint.style = Paint.Style.FILL
Run Code Online (Sandbox Code Playgroud)
更改大小的更新路径
在不是 onDraw 的地方调用它,例如onMeasure对于视图或onBoundChange可绘制对象。如果它没有改变(像这个例子)你可以把这个代码放在你设置你的油漆的地方。
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)
Run Code Online (Sandbox Code Playgroud)
这段代码创建了一个 100x100 的圆角矩形,其顶角以 25 的半径圆角。
绘制路径
onDraw为视图或draw可绘制对象调用此方法。
canvas.drawPath(path, paint)
Run Code Online (Sandbox Code Playgroud)