【问题标题】:Canvas.drawArc() artefactsCanvas.drawArc() 人工制品
【发布时间】:2014-08-06 00:43:36
【问题描述】:

我在自定义视图中的画布上绘制了一条弧线,如下所示。 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);
}

当我在 Galaxy Nexus 4.3 上运行此代码时,会出现以下伪影。

但在 Nexus 5 和 4.4.4 上运行时没有这样的伪影。

我仅通过 (225f, 315f) 等角度和其他一些角度观察到此类人工制品。大多数时候,圆弧的形状是正确的。

有没有办法避免这些伪影?

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

【问题讨论】:

  • 只是为了测试,创建后在您的视图上调用以下命令:myView.setLayerType(View.LAYER_TYPE_SOFTWARE, null); 并查看问题是否仍然出现。可能是硬件加速问题。
  • @kcoppock 你打败了我 :)
  • @kcoppock 试过了。人工制品改变了它们的形状,但仍然存在。
  • 这太奇怪了。如果您将315f 更改为314.98f,该错误就会消失。就是在那个点附近,事情变得不稳定。
  • 想知道这是否发生在其他 4.3 设备中,以验证它是 Android 的错误还是由三星引入的。也很高兴知道它是否发生在早期版本中。

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


【解决方案1】:

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

一个奇怪的地方是,圆弧在外侧以一条垂直的直线越过了指定的结束位置。内部端点似乎没问题。当然,这和其他乱七八糟的行并不能说明问题的原因。

当结束角度恰好是 90 度的倍数时,它似乎会出现。这看起来像是一个数字计算错误、浮点舍入问题等。@kcoppock 评论说 314.98f 已经绕过了这个错误。除了 315.0f 之外,任何值都可以解决问题。

如果涉及代码优化(尝试在尽可能短的线段中绘制圆弧),另一个可行的技巧是通过将圆弧切割成片段来简化圆弧 -> 使用多个 drawArc 调用,每个调用跨越某个最大角度.候选人是30、45、90和180度。关节是否不可见还有待观察......

这有点远,希望这些建议中的任何一个都能奏效。

【讨论】:

  • 感谢您的回答。您很快就可以发表评论了;)
【解决方案2】:

我找到了解决方案! :)

而不是这个:

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

此代码会导致运行速度变慢,但不会产生伪像。 :)

【讨论】:

    猜你喜欢
    • 2019-02-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-01
    相关资源
    最近更新 更多