Вопрос по android, ondraw, android-canvas – Как нарисовать дугу между двумя точками на холсте?

44

У меня есть две точки на холсте, и теперь я могу нарисовать линию между этими точками, как показано на рисунке ниже, используя

Этот кодcanvas.drawLine(p1.x, p1.y, p2.x, p2.y, paint); enter image description here

Я хочу нарисовать дугу между двумя точками, как на картинке ниже.

enter image description here

Как я могу рисовать так

у нас есть эта функция в Android: DrawArc (RectF, float, float, boolean, Paint); RajaReddy PolamReddy
stackoverflow.com/questions/4196749/… vajapravin
@vajapravin Я попробовал это, но эти функции не доступны для холста в Android .. RajaReddy PolamReddy
ты пыталсяandroid-er.blogspot.in/2011/08/canvasdrawarc.html... Вы должны сделать овальную форму на этой позиции vajapravin
@vajapravin Ваш вопрос (и ваш ответ ниже) будет легче понять, если на изображениях выше синие точки будут иметь метки p1 и p2. p.kamps

Ваш Ответ

6   ответов
0

После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)

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

Результат будет выглядеть так

enter image description here

То же самое может быть достигнуто с помощью определения путей и последующей итерации по ним в методе 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

0

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;
}
18

@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);
}
угол между точками будет изменяться динамически, а также положение этих точек. RajaReddy PolamReddy
я должен нарисовать дугу только между этими двумя точками RajaReddy PolamReddy
4-й параметрdrawArc должен быть ложным, иначе он нарисует клин. Стиль также должен бытьSTROKE.
Как я могу рассчитать угол развертки? Не могли бы вы обновить код, чтобы рассчитать это?
Затем необходимо указать начальный угол и угол развертки, см.docs here
0

Вот Лангкиллер. Это рисует кубическую линию от начальной точки через контрольную точку до конечной точки.

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

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

ВычислятьstartAngle, используйте этот код:

int startAngle = (int) (180 / Math.PI * Math.atan2(point.y - point1.y, point.x - point1.x));

Вот,point1 означает, где вы хотите начать рисовать дуги.sweepAngle означает угол между двумя линиями. Мы должны рассчитать это, используя две точки, такие как синие точки на моем изображении Вопроса.

canvas.drawArc (.., .., false, ..) будет рисовать дугу без учета рисования линий, связанных с ее центрами.
Хорошо, спасибо!! :)
Что значит sweeep_angle?
Можете ли вы опубликовать полное решение?
Здесь sweep_angle означает угол между двумя линиями, мы должны рассчитать, что, используя две точки, это самые короткие точки между точками (то есть точки), как синие точки в моем изображении Вопроса ... RajaReddy PolamReddy
4

и это все о вычислении угла развертки и начальных углов.

Я хотел показать дугу, которая представляет прогресс по кругу, идущему сверху вниз.

Таким образом, у меня было значение прогресса от 0 ... 100, и я хочу показать дугу, которая начинается сверху вниз, чтобы заполнить круг, когда прогресс равен 100.

Для расчета SweepAngle я использую:

    int sweepAngle = (int) (360 * (getProgress() / 100.f));

Далее стоит рассчитать startAngle

    int startAngle = 270 - sweepAngle / 2;

Начальный угол рассчитывается таким образом, потому что:

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.

Итак, учитывая, что у меня прогресс на 25%

sweepAngle = 90 degrees (90 degrees is quarter of a circle)
start angle = 225 (45 degrees away from 270)

Если вы хотите, чтобы прогресс шел с других сторон (слева направо, справа налево и т. Д.), Вам нужно только заменить 270 на начальный угол.

Похожие вопросы