Reputation: 10294
I'm trying to draw a 180° arc within an android view.
In the onDraw
method I'm using Canvas::drawArc
like this:
canvas.drawArc(arcRect, 180.0f, 180.0f, false, arcBackgroundPaint);
The Paint that is being used has a strokeCap
of type BUTT
. As you can see in the image below, the ends of the arc do not look quite right. The ends are angled up slightly from the inner diameter to the outer diameter.
Does anyone know why this is happening? Is there a way to fix it other than changing the values passed to drawArc so that it actually draws more than 180 degrees? That seems like a nasty hack that I'd rather avoid.
UPDATE:
As requested, I added code to draw a straight line at the bottom of the arc. I draw the line before I draw the arc so the line is behind. I also made the arc black to get better contrast with the line. Here is the outcome:
Yuck.
Here's one with anti-aliasing turned off for the line and arc...
Upvotes: 3
Views: 1693
Reputation: 10294
For anyone else who comes across this I did find a workaround. Instead of using Canvas::drawArc
, create a Path, add an arc to it and then draw the path on the canvas. Like this:
Path arcPath = new Path();
Rect arcRect = ... // Some rect that will contain the arc
path.addArc(arcRect, 180, 180);
canvas.drawPath(arcPath, backgroundArcPaint);
Then the rendering problem highlighted no longer occurs.
Since my question was not "how do I fix the problem" but rather "why is this a problem" I am not marking this as the correct answer.
Upvotes: 3
Reputation: 2386
drawArc incorrect angles problem will occur if hardware acceleration is on.
Reproduced with real phone (Nexus 5, Android 6.0.1).
How to test:
Add android:hardwareAccelerated="false"
to application tag in AndroidManifest.xml.
NB:
First supported API level of drawArc() is not found in the document, but scaling function of it is from API17.
Hardware Acceleration > Canvas Scaling
https://developer.android.com/guide/topics/graphics/hardware-accel.html
First supported API level
Simple Shapes: 17
Note: 'Simple' shapes are drawRect(), drawCircle(), drawOval(), drawRoundRect(), and drawArc() (with useCenter=false) ...
Updated:
As PICyourBrain wrote in another answer, drawArc()
is a part of reasons this problem occurs.
With drawPath()
, this problem does not occur.
For information:
Not a same shape but drawArc()
with useCenter=true also seems safe to use, as hardware acceleration is not used for it. (Ends of the arc and center of it are connected with line, and the line seems straight.)
Canvas Scaling (same link above)
First supported API level
Complex Shapes: x
Other Q&As related to drawArc()
What's this weird drawArc() / arcTo() bug (graphics glitch) in Android?
[Old]
I'll leave these for your information.
Here are some test results I've tried.
Updated 1-1:
With emulator Nexus5 API10, with arcRect = new RectF(100, 100, 1500, 1400);
.
With emulator Nexus5 API16, this does not happen.
(The difference is existence of (host side) hardware acceleration.)
I thought this seems to be an anti-alias related problem, but this happens no matter arcBackgroundPaint.setAntiAlias(true)
or setDither(true)
are set or not.
NB: This is caused by typo, sorry. Aspect ratio of arcRect should be 1:1 for this test.
With arcRect = new RectF(100, 100, 1400, 1400);
and arcPenWidth = 200f;
With arcRect = new RectF(100, 100, 1500, 1300);
1-2: for comparison
With emulator NexusOne (480x800, HDPI) API10, with arcRect = new RectF(100, 100, 500, 500);
Updated 2: Line extended.
I first thought drawing out of view may cause this, but this is also a emulator bug. (Not a drawArc() specific behavior.)
With emulator API10 in landscape(horizontal) orientation, this occurs.
Calculation of line position seems broken.
Please see the right end of the straight line.
final float lineStartX = arcRect.left - 250f;
final float lineEndX = arcRect.right + 250f;
2-2: Just for a information
View odd behavior sample of view position (or drawing position) out of range.
Updated 3: Emulator bug
Please see the bottom of the image.
Blue line is a background image of desktop.
emulator Nexus5 API10
Update 4: The result seems to depend on style.
With title bar
Update 5: The result seems to depend on line width.
With arcPenWidth = 430f (API10, horizontal)
Slight notch on the right side is seen.
Here's my (first) test code.
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);
}
}
Upvotes: 3