Android 如何在画布上的两点之间绘制圆弧?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11131954/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to draw Arc between two points on the Canvas?
提问by RajaReddy PolamReddy
I have two points in the canvas, now I'm able to draw a line between those points like this below image by using
我在画布上有两个点,现在我可以使用以下图像在这些点之间画一条线
This code canvas.drawLine(p1.x, p1.y, p2.x, p2.y, paint);
这段代码 canvas.drawLine(p1.x, p1.y, p2.x, p2.y, paint);
I want to draw the arc between two points like below image.
我想在两点之间绘制弧线,如下图所示。
How can I draw like this.
我怎么能画成这样。
回答by RajaReddy PolamReddy
Finally I got the solution from this code:
最后我从这段代码中得到了解决方案:
float radius = 20;
final RectF oval = new RectF();
oval.set(point1.x - radius, point1.y - radius, point1.x + radius, point1.y+ radius);
Path myPath = new Path();
myPath.arcTo(oval, startAngle, -(float) sweepAngle, true);
To calculate startAngle
, use this code:
要计算startAngle
,请使用以下代码:
int startAngle = (int) (180 / Math.PI * Math.atan2(point.y - point1.y, point.x - point1.x));
Here, point1
means where you want to start drawing the Arc. sweepAngle
means the angle between two lines. We have to calculate that by using two points like the blue points in my Question image.
此处,point1
表示您要开始绘制圆弧的位置。sweepAngle
表示两条线之间的角度。我们必须使用两个点来计算,比如我的问题图像中的蓝点。
回答by Adil Soomro
Do something like this:
做这样的事情:
@Override
protected void onDraw(Canvas canvas) {
Paint p = new Paint();
RectF rectF = new RectF(50, 20, 100, 80);
p.setColor(Color.BLACK);
canvas.drawArc (rectF, 90, 45, true, p);
}
回答by Ahmad Baraka
I was trying to do something a little different and it's all about calculating sweep and start angles.
我试图做一些不同的事情,这完全是关于计算扫描和开始角度。
I wanted to show an arc that represents progress on a circle that goes from top to bottom.
我想在一个从上到下的圆上显示一个代表进度的圆弧。
So I had progress value from 0...100 and I want to show an arc that start from top to bottom to fill the circle when the progress is 100.
所以我的进度值从 0...100 开始,我想显示一个从上到下开始的弧,以在进度为 100 时填充圆圈。
To calculate the sweepAngle I use:
要计算我使用的sweepAngle:
int sweepAngle = (int) (360 * (getProgress() / 100.f));
Next is to calculate the startAngle
接下来是计算startAngle
int startAngle = 270 - sweepAngle / 2;
Start Angle is calculated this way because:
起始角是这样计算的,因为:
- It's always going to start from the left side, starting from the top to bottom. So starting angle at the top equals 270 (Note that it goes clockwise and 0 = 3 o'clock, so 12 o'clock equals 270 degrees)
- Next I want to calculate how far I'm going to get away from my starting point (270) and to do that I only calculate half of the sweep angle because only half of the arc will be on the left side and the other half on the right side.
- 它总是从左侧开始,从上到下。所以顶部的起始角度等于 270(注意它是顺时针方向的,0 = 3 点钟,所以 12 点钟等于 270 度)
- 接下来我想计算我要离开我的起点(270)多远,为此我只计算扫描角的一半,因为只有一半的弧会在左侧,另一半在右侧。
So considering I have progress of 25%
所以考虑到我有 25% 的进步
sweepAngle = 90 degrees (90 degrees is quarter of a circle)
start angle = 225 (45 degrees away from 270)
If you want the progress to go from other sides (Left to right, right to left etc..) you will only need to replace 270 with the starting the angle.
如果您希望进度从其他方向(从左到右、从右到左等),您只需将 270 替换为起始角度。
回答by j2emanue
first we need to visual how the coordinates are in terms of start and sweep angels then it will become more clear.
首先我们需要可视化坐标在起始和扫掠角方面的情况,然后它会变得更加清晰。
so if you wanted just the right top piece of the circle, we could do something like this:
所以如果你只想要圆的顶部,我们可以这样做:
val rect = RectF(0f, 0f, 500f, 300f)
val paint = Paint()
paint.apply {
strokeWidth = 5f
setStyle(Paint.Style.STROKE)
color = COLOR.BLUE
}
path.addArc(rect, 270f, 90f)
..
..
this starts at 270 (per the diagram above and 'sweeps` 90 degrees forward. you then have this shape:
这从 270 开始(根据上图,向前“扫掠”90 度。然后你就有了这个形状:
let's create one more so you get the hang of it. this time let's use a negative value: we want to create a semi half moon (arc) starting from the right side:
让我们再创建一个,以便您掌握它的窍门。这次让我们使用负值:我们要从右侧开始创建一个半月形(圆弧):
path.addArc(rect, 0f, -180f)
here we started at 0 and 'sweeped` -180 degrees. and the results are:
在这里,我们从 0 开始并“扫过”-180 度。结果是:
回答by Ali Bagheri
a sample for draw arc.
绘制圆弧的示例。
public static Bitmap clipRoundedCorner(Bitmap bitmap, float r, boolean tr, boolean tl, boolean bl, boolean br)
{
int W = bitmap.getWidth();
int H = bitmap.getHeight();
if (r < 0)
r = 0;
int smallLeg = W;
if(H < W )
smallLeg = H;
if (r > smallLeg)
r = smallLeg / 2;
float lineStop = r/2;
Path path = new Path();
path.moveTo(0,0);
if(tr)
{
path.moveTo(0, lineStop);
path.arcTo(new RectF(0,0, r,r), 180, 90, false);
}
path.lineTo(W-lineStop, 0);
if(tl)
path.arcTo(new RectF(W-r,0, W,r), 270, 90, false);
else
path.lineTo(W, 0);
path.lineTo(W, H-lineStop);
if(bl)
path.arcTo(new RectF(W-r,H-r, W,H), 0, 90, false);
else
path.lineTo(W, H);
path.lineTo(lineStop, H);
if(br)
path.arcTo(new RectF(0,H-r, r,H), 90, 90, false);
else
path.lineTo(0,H);
if(tr)
path.lineTo(0,lineStop);
else
path.lineTo(0,0);
Bitmap output = Bitmap.createBitmap(W, H, Config.ARGB_8888);
Canvas canvas = new Canvas(output);
final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(Color.BLACK);
canvas.drawPath(path, paint);
paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
canvas.drawBitmap(bitmap, 0, 0, paint);
return output;
}
回答by Petterson
A simple solution was suggested hereby Langkiller. This draws a cubic line from the start point via the control point to the end point.
Langkiller在这里提出了一个简单的解决方案。这将绘制一条从起点通过控制点到终点的立方线。
Path path = new Path();
float startX = 0;
float startY = 2;
float controlX = 2;
float controlY = 4;
float endX = 4
float endY = 2
conePath.cubicTo(startX, startY, controlX, controlY,endX, endY);
Paint paint = new Paint();
paint.setARGB(200, 62, 90, 177);
paint.setStyle(Paint.Style.FILL);
canvas.drawPath(path, paint)
回答by Hitesh Sahu
I may be late to answer but I got more information.
我可能会迟到回答,但我得到了更多信息。
After Android Lollipop
there are two ways to address this problem
后Android Lollipop
有两种方法可以解决这个问题
public void drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter, Paint paint)
public void drawArc(float left, float top, float right, float bottom, float startAngle, float sweepAngle, boolean useCenter, Paint paint)
public void drawArc(RectF椭圆形,浮动startAngle,浮动sweepAngle,布尔useCenter,油漆油漆)
public void drawArc(向左浮动,向上浮动,向右浮动,浮动底部,浮动起始角,浮动sweepAngle,布尔使用中心,油漆油漆)
Usage:
用法:
RectF rectF = new RectF(left, top, right, bottom);
// method 1
canvas.drawArc (rectF, 90, 45, true, paints[0]);
// method 2
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
canvas.drawArc (left, top, right, bottom, 0, 45, true, paints[1]);
}
Sweep angle is nothing more than angle of Sector which is drawn clockwise eg. for below code
扫描角只不过是顺时针绘制的扇区的角度,例如。对于下面的代码
private void drawArcs(Canvas canvas) {
RectF rectF = new RectF(left, top, right, bottom);
// white arc
canvas.drawArc (rectF, 90, 45, true, paints[0]);
// Green arc
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
canvas.drawArc (left, top, right, bottom, 0, 45, true, paints[1]);
}
// Red stroked arc
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
canvas.drawArc (left, top, right, bottom, 180, 45, true, paints[2]);
}
}
Result will look like this
结果看起来像这样
Same can be achieved with the help of defining Paths and then iterating over them in onDraw method as illustrated in this snippet:
同样可以在定义路径的帮助下实现,然后在 onDraw 方法中迭代它们,如以下代码段所示:
public class ArcDrawable extends Drawable {
private int left, right, top, bottom;
private Paint[] paints = new Paint[3];
private HashMap<Path, Paint> pathMap = new HashMap();
public ArcDrawable() {
// white paint
Paint whitePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
whitePaint.setColor(Color.WHITE);
paints[0]= whitePaint;
// green paint
Paint greenPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
greenPaint.setColor(Color.GREEN);
paints[1]= greenPaint;
// red paint
Paint redPaint =new Paint(Paint.ANTI_ALIAS_FLAG);
redPaint.setColor(Color.RED);
redPaint.setStyle(Paint.Style.STROKE);
paints[2]= redPaint;
}
@Override
public void draw(Canvas canvas) {
//----------USE PATHS----------
// Define and use custom Path
for (Map.Entry<Path, Paint> entry : pathMap.entrySet()) {
// Draw Path on respective Paint style
canvas.drawPath(entry.getKey(), entry.getValue());
}
// -------OR use conventional Style---------
//drawArcs(canvas);
}
//Same result
private void drawArcs(Canvas canvas) {
RectF rectF = new RectF(left, top, right, bottom);
// method 1
canvas.drawArc (rectF, 90, 45, true, paints[0]);
// method 2
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
canvas.drawArc (left, top, right, bottom, 0, 45, true, paints[1]);
}
// method two with stroke
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
canvas.drawArc (left, top, right, bottom, 180, 45, true, paints[2]);
}
}
@Override
protected void onBoundsChange(Rect bounds) {
super.onBoundsChange(bounds);
int width = bounds.width();
int height = bounds.height();
left = bounds.left;
right = bounds.right;
top = bounds.top;
bottom = bounds.bottom;
final int size = Math.min(width, height);
final int centerX = bounds.left + (width / 2);
final int centerY = bounds.top + (height / 2);
pathMap.clear();
//update pathmap using new bounds
recreatePathMap(size, centerX, centerY);
invalidateSelf();
}
private Path recreatePathMap(int size, int centerX, int centerY) {
RectF rectF = new RectF(left, top, right, bottom);
// first arc
Path arcPath = new Path();
arcPath.moveTo(centerX,centerY);
arcPath.arcTo (rectF, 90, 45);
arcPath.close();
// add to draw Map
pathMap.put(arcPath, paints[0]);
//second arc
arcPath = new Path();
arcPath.moveTo(centerX,centerY);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
arcPath.arcTo (rectF, 0, 45);
}
arcPath.close();
// add to draw Map
pathMap.put(arcPath, paints[1]);
// third arc
arcPath = new Path();
arcPath.moveTo(centerX,centerY);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
arcPath.arcTo (rectF, 180, 45);
}
arcPath.close();
// add to draw Map
pathMap.put(arcPath, paints[2]);
return arcPath;
}
@Override
public void setAlpha(int alpha) {
}
@Override
public void setColorFilter(@Nullable ColorFilter colorFilter) {
}
@Override
public int getOpacity() {
return 0;
}
}
Complete source code:
完整的源代码: