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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 06:06:02  来源:igfitidea点击:

How to draw Arc between two points on the Canvas?

androidandroid-canvasondraw

提问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);enter image description here

这段代码 canvas.drawLine(p1.x, p1.y, p2.x, p2.y, paint);enter image description here

I want to draw the arc between two points like below image.

我想在两点之间绘制弧线,如下图所示。

enter image description here

enter image description here

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, point1means where you want to start drawing the Arc. sweepAnglemeans 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:

起始角是这样计算的,因为:

  1. 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)
  2. 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.
  1. 它总是从左侧开始,从上到下。所以顶部的起始角度等于 270(注意它是顺时针方向的,0 = 3 点钟,所以 12 点钟等于 270 度)
  2. 接下来我想计算我要离开我的起点(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

enter image description herefirst we need to visual how the coordinates are in terms of start and sweep angels then it will become more clear.

enter image description here首先我们需要可视化坐标在起始和扫掠角方面的情况,然后它会变得更加清晰。

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 度。然后你就有了这个形状:

enter image description here

enter image description here

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 度。结果是:

enter image description here

enter image description here

回答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 Lollipopthere 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

结果看起来像这样

enter image description here

enter image description here

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:

完整的源代码:

https://github.com/hiteshsahu/Arc-Drawable

https://github.com/hiteshsahu/Arc-Drawable