• 7
name

A PHP Error was encountered

Severity: Notice

Message: Undefined index: userid

Filename: views/question.php

Line Number: 191

Backtrace:

File: /home/prodcxja/public_html/questions/application/views/question.php
Line: 191
Function: _error_handler

File: /home/prodcxja/public_html/questions/application/controllers/Questions.php
Line: 433
Function: view

File: /home/prodcxja/public_html/questions/index.php
Line: 315
Function: require_once

I have the following custom view:

alt text

This I have achieved by using the Canvas' drawArc() method. However, with this drawArc() method I cannot limit the arc's inner radius.

What I'd like to have is something like this:

alt text

where there is only an outer ring left.

What I need is an drawArc() function where I can set the inner radius of the arc. Anyone an idea how to do that?

(BTW, overpainting the inner area doesn't work, because it needs to be transparent. Painting an inner circle with Color.TRANSPARENT after painting the red and blue cones doesn't remove the old color. It just puts another layer on top, which is transparent and through which I can still see the red and blue)

      • 1
    • Does any one know how to make smooth edges of meeting angles, as In my case when I am making ring with 4-5 equal distribution and different colors I can see background at the edges

You can do this:

    Paint paint = new Paint();
    final RectF rect = new RectF();
    //Example values
    rect.set(mWidth/2- mRadius, mHeight/2 - mRadius, mWidth/2 + mRadius, mHeight/2 + mRadius); 
    paint.setColor(Color.GREEN);
    paint.setStrokeWidth(20);
    paint.setAntiAlias(true);
    paint.setStrokeCap(Paint.Cap.ROUND);
    paint.setStyle(Paint.Style.STROKE);
    canvas.drawArc(rect, -90, 360, false, paint);

The key is in paint.setStyle(Paint.Style.STROKE);, it crops the arc's center with the stroke that you define in setStrokeWidth (in the example draws an arc with a radius of mRadius and 20px thick).

Hope it helps!

  • 74
Reply Report

You can paint over the inner area using the PorterDuff xfermode called "Clear." This will erase pixels.

  • 30
Reply Report
      • 1
    • That's a possible solution. But what to do for the case, that there's already something drawn in the inner circle, which I don't want to get overpainted and neither to I want to erase the pixels and redraw it?
      • 2
    • Draw the circle in an offscreen ARGB8888 bitmap, do the clear there, then draw the bitmap onto your Canvas. And that way you also don't have to redraw the circle every time.
      • 2
    • So, after looking into how to actually do this, I'm a bit lost: is an ARGB8888 bitmap a "normal" Bitmap goo.gl/ygTn - and how do I get the same drawing functions as I do with Canvas?
      • 2
    • Update: I figured out that I can actually do it this way Bitmap bm = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); Canvas c = new Canvas(bm); and then draw on the Canvas, which will then write the actual pixels on the Bitmap.
private static final float CIRCLE_LIMIT = 359.9999f;
/**
 * Draws a thick arc between the defined angles, see {@link Canvas#drawArc} for more.
 * This method is equivalent to
 * <pre><code>
 * float rMid = (rInn + rOut) / 2;
 * paint.setStyle(Style.STROKE); // there's nothing to fill
 * paint.setStrokeWidth(rOut - rInn); // thickness
 * canvas.drawArc(new RectF(cx - rMid, cy - rMid, cx + rMid, cy + rMid), startAngle, sweepAngle, false, paint);
 * </code></pre>
 * but supports different fill and stroke paints.
 * 
 * @param canvas
 * @param cx horizontal middle point of the oval
 * @param cy vertical middle point of the oval
 * @param rInn inner radius of the arc segment
 * @param rOut outer radius of the arc segment
 * @param startAngle see {@link Canvas#drawArc}
 * @param sweepAngle see {@link Canvas#drawArc}, capped at &plusmn;360
 * @param fill filling paint, can be <code>null</code>
 * @param stroke stroke paint, can be <code>null</code>
 * @see Canvas#drawArc
 */
public static void drawArcSegment(Canvas canvas, float cx, float cy, float rInn, float rOut, float startAngle,
        float sweepAngle, Paint fill, Paint stroke) {
    if (sweepAngle > CIRCLE_LIMIT) {
        sweepAngle = CIRCLE_LIMIT;
    }
    if (sweepAngle < -CIRCLE_LIMIT) {
        sweepAngle = -CIRCLE_LIMIT;
    }

    RectF outerRect = new RectF(cx - rOut, cy - rOut, cx + rOut, cy + rOut);
    RectF innerRect = new RectF(cx - rInn, cy - rInn, cx + rInn, cy + rInn);

    Path segmentPath = new Path();
    double start = toRadians(startAngle);
    segmentPath.moveTo((float)(cx + rInn * cos(start)), (float)(cy + rInn * sin(start)));
    segmentPath.lineTo((float)(cx + rOut * cos(start)), (float)(cy + rOut * sin(start)));
    segmentPath.arcTo(outerRect, startAngle, sweepAngle);
    double end = toRadians(startAngle + sweepAngle);
    segmentPath.lineTo((float)(cx + rInn * cos(end)), (float)(cy + rInn * sin(end)));
    segmentPath.arcTo(innerRect, startAngle + sweepAngle, -sweepAngle);
    if (fill != null) {
        canvas.drawPath(segmentPath, fill);
    }
    if (stroke != null) {
        canvas.drawPath(segmentPath, stroke);
    }
}

Can be extended to oval arc by duplicating rInn and rOut for x and y directions.

Also wasn't part of the question, but to draw a text in the middle of a segment:

textPaint.setTextAlign(Align.CENTER);
Path midway = new Path();
float r = (rIn + rOut) / 2;
RectF segment = new RectF(cx - r, cy - r, cx + r, cy + r);
midway.addArc(segment, startAngle, sweepAngle);
canvas.drawTextOnPath("label", midway, 0, 0, textPaint);
  • 17
Reply Report
      • 2
    • this code is amazing! However I have a question, is there way I can make the lines between the circles to have a different color than the circles perimeter color?
      • 1
    • @Snake, you'll have to split segmentPath.*To() calls into multiple Paths and draw each separately with your select stroke colors. You can do what you discribe with 2 paths: moveTo,lineTo,moveTo,lineTo and moveTo,arcTo,moveTo,arcTo. You'll still have to keep the current one to have something to fill.
      • 1
    • It is not necessary to use lineTo. For the second arcTo() add false as a final parameter; this will draw a line from the end of the first arc to the beginning of the second. Then close() the path.

You can try following ShapeDrawable

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
<item>
    <shape android:shape="oval" >
        <size
            android:height="56dp"
            android:width="56dp" />

        <stroke
            android:width="10dp"
            android:color="#0000ff" />
    </shape>
</item>
<item>
    <shape android:shape="oval" >
        <size
            android:height="24dp"
            android:width="25dp" />

        <stroke
            android:dashGap="10dp"
            android:dashWidth="10dp"
            android:width="10dp"
            android:color="#FF0000" />
    </shape>
</item>

  • 2
Reply Report

drawing Circle and Arc. the following code is little dirty but it may help

        int sweepAngle sweepAngle = (360/7)%360;
    int startAngle = -90;
    int x = getWidth()/2;
    int y = getHeight()/2;
    int radius;
    radius = getWidth()/2-50;
    paint.setStyle(Paint.Style.STROKE);
    paint.setStrokeWidth(50);
    paint.setColor(Color.WHITE);

    paint.setColor(Color.parseColor("#CD5C5C"));
    mBarPaintFill.setAntiAlias(true);

    canvas.drawCircle(x , y , radius, paint);
    paint.setColor(Color.BLUE);
    for (int i = 1 ; i<=5 ; i++){

        canvas.drawArc(x-radius,y-radius,x+radius,y+radius,startAngle,sweepAngle,false,paint);
        startAngle = (startAngle + sweepAngle+20)%360;
    }

enter image description here

  • 2
Reply Report