Customize UI to draw pie chart

Catalogue of series articles

  1. Customize UI Basics
  2. Customize UI to draw pie chart

preface

This series of articles is mainly based on the throwing line HenCoderPlus course source code To analyze learning.

Draw pie chart

Create paint objects

We need to create a brush 🖌 Paint to draw our pie chart.

public class PieChart extends View {
    // Radius of pie chart
    private static final int RADIUS = (int) Utils.dp2px(150);
    // Anti aliasing (can effectively solve the problem of Burr)
    Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
    // Distribution area of pie chart
    RectF bounds = new RectF();

	// This constructor is called by default
    public PieChart(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }
}

Set layout location

If your view does not require special control over its size, you only need to replace one method, onSizeChanged(). The system will call onSizeChanged() the first time you allocate the size of your view. If the view size changes for any reason, the system will call this method again. Calculate the position, size, and any other values related to the view size in onSizeChanged(), instead of recalculating each time you draw.

Excerpt from Andorid official documents: Handling layout events

public class PieChart extends View {
    // Radius of pie chart
    private static final int RADIUS = (int) Utils.dp2px(150);
    // Anti aliasing (can effectively solve the problem of Burr)
    Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
    // Distribution area of pie chart
    RectF bounds = new RectF();

    public PieChart(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    /**
     * Called when the size of this view changes.
     */
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        // Recalculate the position of the pie chart according to the width of the View
        int ww = getWidth() / 2;
        // Sets the position of the rectangle
        // Four parameters: left, top, right and bottom
        // Left: the position of the point on the left of the rectangle in the x-axis direction
        // top: the position of the point on the upper edge of the rectangle in the y-axis direction
        // Right: the position of the point on the right side of the rectangle in the x-axis direction
        // Bottom: the position of the point at the bottom of the rectangle in the y-axis direction
        bounds.set(ww - RADIUS, ww - RADIUS, ww + RADIUS, ww + RADIUS);
    }
}
  • android. graphics. Description of the four parameters of rectf#set (float, float, float, float)
parameterexplain
leftThe position of the point to the left of the rectangle in the x-axis direction
topThe position of the point on the upper edge of the rectangle in the y-axis direction
rightThe position of the point to the right of the rectangle in the x-axis direction
bottomThe position of the point on the lower side of the rectangle in the y-axis direction

Experimental effect

Let's draw the range of bounds we set.

public class PieChart extends View {
    // Radius of pie chart
    private static final int RADIUS = (int) Utils.dp2px(150);
    // Anti aliasing (can effectively solve the problem of Burr)
    Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
    // Distribution area of pie chart
    RectF bounds = new RectF();

    public PieChart(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    /**
     * Called when the size of this view changes.
     */
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        // Recalculate the position of the pie chart according to the width of the View
        int ww = getWidth() / 2;
        bounds.set(ww - RADIUS, ww - RADIUS, ww + RADIUS, ww + RADIUS);
    }

	// Rewrite the method to define the drawing content
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawRect(bounds, paint);
    }
}

Customize drawing content

Rewrite Android view. View #ondraw method to realize custom drawing.

/**
 * Implement this to do your drawing.
 *
 * @param canvas the canvas on which the background will be drawn
 */
protected void onDraw(Canvas canvas) {

}

Draw sector

public class PieChart extends View {

	// Distribution area of pie chart
    RectF bounds = new RectF();
	// I omitted the same code as before
		
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        // Draw sector
        canvas.drawArc(bounds, 0, 120, true, paint);
    }
}

The method used to draw the sector above is: Android graphics. Canvas#drawArc(android.graphics.RectF, float, float, boolean, android.graphics.Paint).

parameterexplain
RectFFan display area
startAngleSector start angle
sweepAngleFan sweep angle
useCenterWhether to use center point.

true: sector is drawn (see Figure 1 below)
false: arc is drawn (see Figure 3 below)
paintpaint brush
  • In order to make it easier for you to understand, I also draw the boundaries for comparison.
    • The gray area is the drawing range of boundaries.
    • The black sector is what we draw.

Draw sector chart

public class PieChart extends View {
    // Radius of pie chart
    private static final int RADIUS = (int) Utils.dp2px(150);
    // Anti aliasing (can effectively solve the problem of Burr)
    Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
    // Distribution area of pie chart
    RectF bounds = new RectF();
    // Start drawing from the fourth quadrant of the coordinate axis
    int[] angles = {60, 100, 120, 80};
    int[] colors = {
            Color.parseColor("#2979FF"),
            Color.parseColor("#C2185B"),
            Color.parseColor("#009688"),
            Color.parseColor("#FF8F00")
    };

    public PieChart(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        // Recalculate the position of the pie chart according to the width of the View
        int ww = getWidth() / 2;
        bounds.set(ww - RADIUS, ww - RADIUS, ww + RADIUS, ww + RADIUS);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        // draw rectangle
        // canvas.drawRect(bounds, paint);
        int currentAngle = 0;
        for (int i = 0; i < angles.length; i++) {
            paint.setColor(colors[i]);
            canvas.drawArc(bounds, currentAngle, angles[i], true, paint);
            currentAngle += angles[i];
        }
    }
}
  • Figure 2: canvas is added in onDraw drawRect(bounds, paint); Drawing of.
  • The drawing sequence of the sector is shown in Figure 2 📌 The order of.

Pull the fan out

public class PieChart extends View {
	// Removed some duplicate code

    // Offset of pie chart from coordinate axis
    private static final int OFFSET = (int) Utils.dp2px(20);
    // Index value of the sector pulled outward
    private static final int PULLED_OUT_INDEX = 2;

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        int currentAngle = 0;
        for (int i = 0; i < angles.length; i++) {
            paint.setColor(colors[i]);
            // Save means to save the current view
            canvas.save();
            if (i == PULLED_OUT_INDEX) {
                int tempAngle = angles[i] / 2;
                canvas.translate(
                        (float) Math.cos(Math.toRadians(currentAngle + tempAngle)) * OFFSET,
                        (float) Math.sin(Math.toRadians(currentAngle + tempAngle)) * OFFSET
                );
            }
            canvas.drawArc(bounds, currentAngle, angles[i], true, paint);
            // Restore the canvas view after translation
            canvas.restore();
            currentAngle += angles[i];
        }
    }
}

Principle analysis

Official Android documentation: Canvas#translate

Look directly at the drawing and see the drawing sequence:

stepexplain
1The fan is drawn on the rectangular boundaries.
2Draw a blue fan. Note: with the center of the circle as the coordinate origin, the drawing sequence starts from the fourth quadrant and ends from the first quadrant.
3Draw a Burgundy fan.
4Canvas executes the translate method to move the drawing area to the upper left.
5Draw an olive green fan on the transformed Canvas.
6Restore the Canvas before transformation and draw an orange fan.

Summary:

  • The operation of pulling the sector out is based on Canvas#translate Implemented.
  • Restore the transformed Canvas based on Canvas save(); And Canvas restore(); To finish it.

So, without canvas save(); And canvas restore(); What will happen?

Summary:

  • Canvas#translate It cannot be recovered later. The third and fourth sectors will stick together and become a large piece.

appendix

Keywords: Android canvas

Added by torrentmasta on Sat, 22 Jan 2022 05:10:08 +0200