【问题标题】:Android: looking for a drawArc() method with inner & outer radiusAndroid:寻找具有内外半径的 drawArc() 方法
【发布时间】:2011-04-21 22:12:50
【问题描述】:

我有以下自定义视图:

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

我想要的是这样的:

只剩下一个外环。

我需要的是一个drawArc() 函数,我可以在其中设置圆弧的内半径。有人知道怎么做吗?

(顺便说一句,重绘内部区域是行不通的,因为它需要透明。在绘制红色和蓝色圆锥后用Color.TRANSPARENT绘制一个内圈不会删除旧颜色。它只是放了另一层顶部是透明的,通过它我仍然可以看到红色和蓝色)

【问题讨论】:

  • 你能在得到最终要求后发布你最新的代码吗?谢谢
  • 有谁知道如何使会合角的边缘光滑,就像我在制作 4-5 个均匀分布和不同颜色的戒指时,我可以在边缘看到背景

标签: android 2d draw geometric-arc


【解决方案1】:

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

【讨论】:

  • 这是一个可能的解决方案。但是对于这种情况该怎么办,内圈已经画了一些东西,我不想被过度绘制,也不想擦除像素并重新绘制它?
  • 在屏幕外的 ARGB8888 位图中绘制圆圈,在此处进行清除,然后将位图绘制到 Canvas 上。这样您也不必每次都重新绘制圆圈。
  • 所以,在研究了如何实际执行此操作后,我有点迷茫:ARGB8888 位图是“正常”位图goo.gl/ygTn - 以及如何获得与我相同的绘图功能用 Canvas 做什么?
  • 更新:我发现我实际上可以这样做 Bitmap bm = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);画布 c = 新画布(bm);然后在 Canvas 上绘制,然后将实际像素写入 Bitmap。
【解决方案2】:

你可以这样做:

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

关键在paint.setStyle(Paint.Style.STROKE);,它使用您在 setStrokeWidth 中定义的描边裁剪圆弧的中心(在示例中绘​​制半径为 mRadius 和 20px 厚的圆弧)。

希望对你有帮助!

【讨论】:

  • 像魅力一样工作!有时我忘记从容器中减去笔画,我得到一个裁剪的圆圈。谢谢。
  • 如果你使用paint.setStrokeCap(Paint.Cap.BUTT);而不是paint.setStrokeCap(Paint.Cap.ROUND);,你就会得到问题想要的结果。
  • 我认为您可以放心地使用canvas.drawArc(rect,0,360,false,paint); 而不是-90
  • 你能给这个设置一个渐变颜色(比如着色器)吗?
  • Paint.Cap.BUTT 是默认值,所以你不妨删除paint.setStrokeCap(); 这一行。
【解决方案3】:
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);
    }
}

可以通过在 x 和 y 方向上复制 rInnrOut 来扩展到椭圆弧。

也不是问题的一部分,而是在段的中间画一段文字:

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

【讨论】:

  • 这段代码太棒了!但是我有一个问题,有没有办法让圆圈之间的线条与圆圈周边颜色不同?
  • @Snake,您必须将segmentPath.*To() 调用拆分为多个Paths,并使用您选择的笔触颜色分别绘制。您可以使用 2 条路径执行您所描述的操作:moveTo,lineTo,moveTo,lineTomoveTo,arcTo,moveTo,arcTo。您仍然必须保留当前的内容才能填充。
  • 我“认为”我隐约明白了。由于我仍然需要您的帮助,因此我按照您的建议创建了另一个问题。期待您的帮助。这是链接stackoverflow.com/questions/27850634/…
  • 不必使用lineTo。对于第二个arcTo() 添加false 作为最终参数;这将从第一个弧的末端到第二个弧的开始画一条线。然后close()路径。
【解决方案4】:

你可以尝试关注ShapeDrawable

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
<item>
    <shape android:shape="oval" >
        <size
            android:height="56dp"
            android:width="56dp" />

        <stroke
            android:width="10dp"
            android:color="#0000ff" />
    </shape>
</item>
<item>
    <shape android:shape="oval" >
        <size
            android:height="24dp"
            android:width="25dp" />

        <stroke
            android:dashGap="10dp"
            android:dashWidth="10dp"
            android:width="10dp"
            android:color="#FF0000" />
    </shape>
</item>

【讨论】:

    【解决方案5】:

    画圆和弧。以下代码有点脏,但它可能会有所帮助

            int sweepAngle sweepAngle = (360/7)%360;
        int startAngle = -90;
        int x = getWidth()/2;
        int y = getHeight()/2;
        int radius;
        radius = getWidth()/2-50;
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeWidth(50);
        paint.setColor(Color.WHITE);
    
        paint.setColor(Color.parseColor("#CD5C5C"));
        mBarPaintFill.setAntiAlias(true);
    
        canvas.drawCircle(x , y , radius, paint);
        paint.setColor(Color.BLUE);
        for (int i = 1 ; i<=5 ; i++){
    
            canvas.drawArc(x-radius,y-radius,x+radius,y+radius,startAngle,sweepAngle,false,paint);
            startAngle = (startAngle + sweepAngle+20)%360;
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-07-02
      • 1970-01-01
      • 2021-09-28
      • 1970-01-01
      • 2019-06-29
      • 2015-06-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多