Android:寻找具有内半径和外半径的drawArc()方法

znq*_*znq 34 android 2d draw geometric-arc

我有以下自定义视图:

替代文字

这是我通过使用Canvas的drawArc()方法实现的.但是,使用这种drawArc()方法我不能限制弧的内半径.

我想拥有的是这样的:

替代文字

只剩下一个外环的地方.

我需要的是一个drawArc()函数,我可以设置弧的内半径.任何人都知道如何做到这一点?

(顺便说一句,覆盖内部区域不起作用,因为它需要是透明的.Color.TRANSPARENT在绘制红色和蓝色锥体之后绘制内部圆圈不会移除旧颜色.它只是将另一层放在顶部,这是透明的我仍然可以看到红色和蓝色)

小智 73

你可以这样做:

    Paint paint = new Paint();
    final RectF rect = new RectF();
    //Example values
    rect.set(mWidth/2- mRadius, mHeight/2 - mRadius, mWidth/2 + mRadius, mHeight/2 + mRadius); 
    paint.setColor(Color.GREEN);
    paint.setStrokeWidth(20);
    paint.setAntiAlias(true);
    paint.setStrokeCap(Paint.Cap.ROUND);
    paint.setStyle(Paint.Style.STROKE);
    canvas.drawArc(rect, -90, 360, false, paint);
Run Code Online (Sandbox Code Playgroud)

关键是paint.setStyle(Paint.Style.STROKE);,它使用您在setStrokeWidth中定义的笔划裁剪弧的中心(在示例中绘​​制半径为mRadius且厚度为20px的弧).

希望能帮助到你!

  • 我认为你可以安全地使用`canvas.drawArc(rect,0,360,false,paint);`而不是-90 (6认同)
  • 如果你使用`paint.setStrokeCap(Paint.Cap.BUTT);`而不是`paint.setStrokeCap(Paint.Cap.ROUND);`你会得到问题所需要的. (4认同)

Rom*_*Guy 30

您可以使用名为"Clear"的PorterDuff xfermode在内部区域上绘画.这将擦除像素.

  • 在屏幕外的ARGB8888位图中绘制圆,在那里进行清除,然后将位图绘制到Canvas上。这样,您也不必每次都重新绘制圆圈。 (2认同)
  • 更新:我发现我实际上可以这样做Bitmap bm = Bitmap.createBitmap(w,h,Bitmap.Config.ARGB_8888); 画布c =新画布(bm); 然后在Canvas上绘制,然后在Bitmap上写下实际的像素. (2认同)

TWi*_*Rob 16

private static final float CIRCLE_LIMIT = 359.9999f;
/**
 * Draws a thick arc between the defined angles, see {@link Canvas#drawArc} for more.
 * This method is equivalent to
 * <pre><code>
 * float rMid = (rInn + rOut) / 2;
 * paint.setStyle(Style.STROKE); // there's nothing to fill
 * paint.setStrokeWidth(rOut - rInn); // thickness
 * canvas.drawArc(new RectF(cx - rMid, cy - rMid, cx + rMid, cy + rMid), startAngle, sweepAngle, false, paint);
 * </code></pre>
 * but supports different fill and stroke paints.
 * 
 * @param canvas
 * @param cx horizontal middle point of the oval
 * @param cy vertical middle point of the oval
 * @param rInn inner radius of the arc segment
 * @param rOut outer radius of the arc segment
 * @param startAngle see {@link Canvas#drawArc}
 * @param sweepAngle see {@link Canvas#drawArc}, capped at &plusmn;360
 * @param fill filling paint, can be <code>null</code>
 * @param stroke stroke paint, can be <code>null</code>
 * @see Canvas#drawArc
 */
public static void drawArcSegment(Canvas canvas, float cx, float cy, float rInn, float rOut, float startAngle,
        float sweepAngle, Paint fill, Paint stroke) {
    if (sweepAngle > CIRCLE_LIMIT) {
        sweepAngle = CIRCLE_LIMIT;
    }
    if (sweepAngle < -CIRCLE_LIMIT) {
        sweepAngle = -CIRCLE_LIMIT;
    }

    RectF outerRect = new RectF(cx - rOut, cy - rOut, cx + rOut, cy + rOut);
    RectF innerRect = new RectF(cx - rInn, cy - rInn, cx + rInn, cy + rInn);

    Path segmentPath = new Path();
    double start = toRadians(startAngle);
    segmentPath.moveTo((float)(cx + rInn * cos(start)), (float)(cy + rInn * sin(start)));
    segmentPath.lineTo((float)(cx + rOut * cos(start)), (float)(cy + rOut * sin(start)));
    segmentPath.arcTo(outerRect, startAngle, sweepAngle);
    double end = toRadians(startAngle + sweepAngle);
    segmentPath.lineTo((float)(cx + rInn * cos(end)), (float)(cy + rInn * sin(end)));
    segmentPath.arcTo(innerRect, startAngle + sweepAngle, -sweepAngle);
    if (fill != null) {
        canvas.drawPath(segmentPath, fill);
    }
    if (stroke != null) {
        canvas.drawPath(segmentPath, stroke);
    }
}
Run Code Online (Sandbox Code Playgroud)

可以通过复制rInnrOutx和y方向扩展到椭圆弧.

也不是问题的一部分,而是在段的中间绘制文本:

textPaint.setTextAlign(Align.CENTER);
Path midway = new Path();
float r = (rIn + rOut) / 2;
RectF segment = new RectF(cx - r, cy - r, cx + r, cy + r);
midway.addArc(segment, startAngle, sweepAngle);
canvas.drawTextOnPath("label", midway, 0, 0, textPaint);
Run Code Online (Sandbox Code Playgroud)