Canvas.drawArc()artefacts

时间:2014-08-06 00:43:37

标签: android android-canvas android-custom-view

我在自定义视图中在画布上绘制一个圆弧,如下所示。 Paintrectangle是在onDraw()之外定义的,并且为了简单起见而添加到其中。

protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);

    RectF rectangle = new RectF(60f, 60f, 480f, 480f);

    Paint paint = new Paint();
    paint.setAntiAlias(true);
    paint.setColor(0x40000000);
    paint.setStyle(Paint.Style.STROKE);
    paint.setStrokeWidth(120);

    canvas.drawArc(rectangle, 225f, 315f, false, paint);
}

当我使用4.3在Galaxy Nexus上运行此代码时,会出现以下人为因素。 enter image description here

在使用4.4.4的Nexus 5上运行时没有这样的假象。 enter image description here

我通过像(225f,315f)这样的角度和其他一些角度来观察这些假象。大多数情况下,弧形的形状是正确的。

有没有办法避免那些人工制品?

更新:我尝试使用setLayerType()使用软件,硬件和无图层。人工制品改变了形式,但仍然存在。

2 个答案:

答案 0 :(得分:2)

我是StackOverflow新手,想添加评论但不能(分数不足),所以不得不把我的评论放在答案中!

奇怪的是,电弧超出了指定的终点位置,外侧有一条直的垂直线。内端点似乎没问题。当然,这个和其他乱七八糟的线条并没有说明导致问题的原因。

当结束角度精确 90度的倍数时,似乎会出现。这看起来像一个数字计算错误,浮动圆整问题等。@ kcoppock评论说314.98f已经绕过了这个bug。可能除了315.0f以外的任何值都可能有效。

如果涉及代码优化(尝试以尽可能小的线段绘制弧),可能有效的另一个技巧是通过将弧切成碎片来简化弧 - >使用多个drawArc调用,每个调用跨越一定的最大角度。考生分别为30度,45度,90度和180度。如果关节不可见,仍然有待观察......

这有点远,希望这些建议都可行。

答案 1 :(得分:0)

我找到了解决方案! :)

而不是:

RectF rectangle = new RectF(60f, 60f, 480f, 480f);

Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setColor(0x40000000);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(120);

canvas.drawArc(rectangle, 225f, 315f, false, paint);

使用此:

RectF rectangle = new RectF(60f, 60f, 480f, 480f);

Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setColor(0x40000000);
paint.setStyle(Paint.Style.FILL);

float strokeWidth = 120;
float startAngle = 225f;
float sweepAngle = 315f;

RectF pathRect = new RectF();
Path path = new Path();
float s = strokeWidth / 2;
pathRect.left = rectangle.left - s;
pathRect.right = rectangle.right + s;
pathRect.top = rectangle.top - s;
pathRect.bottom = rectangle.bottom + s;
path.arcTo(pathRect, startAngle, sweepAngle);
pathRect.left = rectangle.left + s;
pathRect.right = rectangle.right - s;
pathRect.top = rectangle.top + s;
pathRect.bottom = rectangle.bottom - s;
path.arcTo(pathRect, startAngle + sweepAngle, -sweepAngle);
path.close();
canvas.drawPath(path, paint);

此代码导致运行速度较慢,但​​它不会产生伪影。 :)