Catalogue of series articles
preface
This series of articles is mainly based on the throwing line HenCoderPlus course source code To analyze learning.
Draw pie chart
- Throwing line course source code: PieChart.java
- Official Android documentation: Custom drawing
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)
parameter | explain |
---|---|
left | The position of the point to 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 to the right of the rectangle in the x-axis direction |
bottom | The 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).
parameter | explain |
---|---|
RectF | Fan display area |
startAngle | Sector start angle |
sweepAngle | Fan sweep angle |
useCenter | Whether to use center point. true: sector is drawn (see Figure 1 below) false: arc is drawn (see Figure 3 below) |
paint | paint 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:
step | explain |
---|---|
1 | The fan is drawn on the rectangular boundaries. |
2 | Draw 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. |
3 | Draw a Burgundy fan. |
4 | Canvas executes the translate method to move the drawing area to the upper left. |
5 | Draw an olive green fan on the transformed Canvas. |
6 | Restore 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
- Android Developer: Custom view components
- Throwing line official website: Throw line
- Thank you for the tutorial and source code provided by the boss, so that you can learn the content of custom UI systematically.
- rengwuxian/HenCoderPlus
- rengwuxian/HenCoderPlus3