为什么Canvas :: drawArc方法绘制的角度不正确?

时间:2017-11-13 16:08:58

标签: android canvas draw

我正在尝试在android视图中绘制180°弧。 在onDraw方法中,我正在使用Canvas::drawArc,如下所示:

canvas.drawArc(arcRect, 180.0f, 180.0f, false, arcBackgroundPaint);

正在使用的Paint的strokeCap类型为BUTT。正如您在下图中看到的那样,弧的末端看起来不太正确。两端从内径到外径略微倾斜。

180 degree arc

有谁知道为什么会这样?有没有办法解决它除了更改传递给drawArc的值,以便它实际绘制超过180度?这似乎是一个讨厌的黑客,我宁愿避免。

更新: 根据要求,我添加了代码以在弧的底部绘制一条直线。我绘制弧线之前画线,所以线条在后面。我还将弧线设为黑色,以便与线条形成更好的对比。结果如下: enter image description here 呸。

这是一个关闭线和弧的抗锯齿功能...... enter image description here

2 个答案:

答案 0 :(得分:3)

drawArc如果出现硬件加速,将出现错误的角度问题。

转载真人手机(Nexus 5,Android 6.0.1)。

如何测试:
android:hardwareAccelerated="false"添加到AndroidManifest.xml中的应用程序标记。

NB:
在文档中找不到第一个支持的drawArc()API级别,但它的缩放功能来自API17。

硬件加速>画布缩放
https://developer.android.com/guide/topics/graphics/hardware-accel.html

  

首先支持的API级别
  简单形状:17
  注意:'简单'形状是drawRect(),drawCircle(),drawOval(),drawRoundRect()和drawArc()(使用useCenter = false)......

更新: 正如PICyourBrain在另一个回答中所写,drawArc()是出现此问题的部分原因。

使用drawPath()时,不会出现此问题。

有关信息:
形状不同但使用useCenter = true的drawArc()似乎也可以安全使用,因为硬件加速不用于它。 (弧的末端和中心与线连接,线看起来笔直。)

Canvas Scaling(上面的相同链接)

  

首先支持的API级别
  复杂形状:x

其他Q&与drawArc()

相关

Canvas.drawArc() artefacts

What's this weird drawArc() / arcTo() bug (graphics glitch) in Android?

[旧]
我会留下这些信息。

以下是我尝试过的一些测试结果。

更新了1-1:

使用模拟器Nexus5 API10,arcRect = new RectF(100, 100, 1500, 1400);enter image description here 使用模拟器Nexus5 API16,这不会发生 (不同之处在于(主机端)硬件加速的存在。)

我认为这似乎是一个与别名相关的问题,但无论arcBackgroundPaint.setAntiAlias(true)setDither(true)是否设置,都会发生这种情况。

注意:这是由错字引起的,抱歉。此测试的arcRect长宽比应为1:1 使用arcRect = new RectF(100, 100, 1400, 1400);arcPenWidth = 200f;
enter image description here

使用arcRect = new RectF(100, 100, 1500, 1300);
enter image description here

1-2:用于比较
使用模拟器NexusOne(480x800,HDPI)API10,arcRect = new RectF(100, 100, 500, 500); enter image description here

更新2:延长线。
我首先想到绘制视图可能会导致这种情况,但这也是一个模拟器错误。 (不是drawArc()特定的行为。)
对于横向(水平)方向的仿真器API10,会发生这种情况 线位置的计算似乎被打破了 请参阅直线的右端。

final float lineStartX = arcRect.left - 250f;
final float lineEndX = arcRect.right + 250f;

模拟器Nexus5 API10 enter image description here

水平(API10) enter image description here

垂直(API10)
enter image description here

2-2:仅供参考 查看视图位置(或绘图位置)的奇怪行为样本超出范围。

enter image description here enter image description here

更新3:模拟器错误

请参阅图片底部 蓝线是桌面的背景图像 模拟器Nexus5 API10

enter image description here

更新4:结果似乎取决于风格 带标题栏
enter image description here

没有标题栏
enter image description here

更新5:结果似乎取决于线宽。

arcPenWidth = 430f(API10,水平)
可以看到右侧有轻微凹口 enter image description here

用440f
enter image description here

450f
enter image description here

这是我的(第一个)测试代码。

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;

final class TestView extends View
{
    RectF arcRect;
    Paint arcBackgroundPaint;
    Paint linePaint;

    public TestView(final Context context, final AttributeSet attrs)
    {
        super(context, attrs);
        //arcRect = new RectF(100, 100, 500, 500);
        arcRect = new RectF(100, 100, 1500, 1500); // fixed (old: 1500, 1400)
        arcBackgroundPaint = new Paint();
        arcBackgroundPaint.setColor(0xFFFFFFFF);
        arcBackgroundPaint.setStyle(Paint.Style.STROKE);
        arcBackgroundPaint.setStrokeCap(Paint.Cap.BUTT);
        arcBackgroundPaint.setStrokeWidth(200f);
        linePaint = new Paint();
        linePaint.setColor(0xFF00FF00);
        linePaint.setStyle(Paint.Style.STROKE);
        linePaint.setStrokeCap(Paint.Cap.BUTT);
        linePaint.setStrokeWidth(2f);
    }

    @Override
    protected void onDraw(final Canvas canvas)
    {
        super.onDraw(canvas);
        canvas.drawArc(arcRect, 180.0f, 180.0f, false, arcBackgroundPaint);
        final float lineStartX = arcRect.left - 50f;
        final float lineEndX = arcRect.right + 50f;
        final float lineY = arcRect.centerY();
        canvas.drawLine(lineStartX, lineY, lineEndX, lineY, linePaint);
    }
}

答案 1 :(得分:2)

对于遇到此问题的其他人,我确实找到了解决方法。而不是使用Canvas::drawArc,创建一个路径,向其添加一个弧,然后在画布上绘制路径。像这样:

Path arcPath = new Path();
Rect arcRect = ... // Some rect that will contain the arc
path.addArc(arcRect, 180, 180); 
canvas.drawPath(arcPath, backgroundArcPaint);

然后突出显示渲染问题不再出现。

由于我的问题不是"我该如何解决问题"而是"为什么这是一个问题"我并不认为这是正确答案。