The requirements in the project can be realized by searching the MPAndroidChart library at that time, but it is not very cool to reference such a large library just for one requirement, so I plan to define one by myself. Reference + practice
First, the convention of the effect map
Second, making
The code address, welcome to correct https://github.com/MNXP/XPPieChart
Third, train of thought
Get the current Paint Angle based on the animation. 4. Get the color used for Paint based on the current Angle.Copy the code
Four, implementation,
1. Initialize data for hollow graph (draw a small circle in the center of a large circle)
paint = new Paint();
paint.setAntiAlias(true); paint.setStyle(Paint.Style.FILL_AND_STROKE); screenW = DensityUtils.getScreenWidth(context); int width = DensityUtils.dip2px(context, 15); Int widthXY = denSityutils.dip2px (context, 10); Int pieCenterX = screenW / 2; Int pieCenterY = screenW / 3; Int pieRadius = screenW / 4; Rect pieOval = new RectF(); pieOval.left = pieCenterX - pieRadius; pieOval.top = pieCenterY - pieRadius + widthXY; pieOval.right = pieCenterX + pieRadius; pieOval.bottom = pieCenterY + pieRadius + widthXY; Rect pieOvalIn = new RectF(); pieOvalIn.left = pieOval.left + width; pieOvalIn.top = pieOval.top + width; pieOvalIn.right = pieOval.right - width; pieOvalIn.bottom = pieOval.bottom - width; PiePaintIn = new Paint(); piePaintIn.setAntiAlias(true);
piePaintIn.setStyle(Paint.Style.FILL);
piePaintIn.setColor(Color.parseColor("#f4f4f4"));
Copy the code
2. Calculate the Angle occupied according to the data
Use recursion to ensure that the values of cakeValues must sum to 100, and then calculate the Angle based on the valuesCopy the code
private void settleCakeValues(int i) {
float sum = getSum(cakeValues, i);
CakeValue value = cakeValues.get(i);
if (sum <= 100f) {
value.setItemValue(100f - sum);
cakeValues.set(i, value);
} else{ value.setItemValue(0); settleCakeValues(i - 1); }}Copy the code
3. Get the current drawing Angle based on the animation
CurAngle is the current drawing Angle, and drawArc() is the drawing methodCopy the code
cakeValueAnimator.addUpdateListener(new AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float mAngle = obj2Float(animation.getAnimatedValue("angle")); curAngle = mAngle; drawArc(); }});Copy the code
4. Get the color used for Paint based on the current Angle
SetColor (color.parsecolor (cakeValues. Get (colorIndex).getcolors ()))); To set the paint colorCopy the code
private int getCurItem(float curAngle) {
int res = 0;
for (int i = 0; i < itemFrame.length; i++) {
if (curAngle <= itemFrame[i] * ANGLE_NUM) {
res = i;
break; }}return res;
}
Copy the code
5. Dynamically draw what is to be drawn and what has been drawn
The most important step I need is 4 classes, with different colorsCopy the code
Draws the sector of the current color, the start position of the curStartAngle sector, and the end position of the curSweepAngle sectorCopy the code
paint.setColor(Color.parseColor(cakeValues.get(colorIndex).getColors()));
float curStartAngle = 0;
float curSweepAngle = curAngle;
if (curItem > 0) {
curStartAngle = itemFrame[curItem - 1] * ANGLE_NUM;
curSweepAngle = curAngle - (itemFrame[curItem - 1] * ANGLE_NUM);
}
canvas.drawArc(pieOval, curStartAngle, curSweepAngle, true, paint);
Copy the code
Draw the sector that has been drawn. Draw the sector according to the curItem judgmentCopy the code
for (int i = 0; i < curItem; i++) {
paint.setColor(Color.parseColor(cakeValues.get(i).getColors()));
if (i == 0) {
canvas.drawArc(pieOval, startAngle,(float) cakeValues.get(i).getItemValue() * ANGLE_NUM, true, paint);
continue;
}
canvas.drawArc(pieOval,itemFrame[i - 1] * ANGLE_NUM,(float) cakeValues.get(i).getItemValue() * ANGLE_NUM, true, paint);
}
Copy the code
Draw the center circleCopy the code
canvas.drawArc(pieOvalIn, 0, 360, true, piePaintIn);
Copy the code
6. Pay special attention
IsFirst determines whether it is the first time to draw (after drawing, the home button enters the background and enters again, without dynamic drawing)Copy the code
@Override
protected void onDraw(Canvas canvas) {
if (isFirst && isDrawByAnim) {
drawCakeByAnim();
}
isFirst = false;
}
Copy the code
IsDrawByAnim Determines whether drawCake() needs to be animated to draw a statically drawn pie chartCopy the code
public void surfaceCreated(SurfaceHolder holder) {
if(! isFirst||! isDrawByAnim) drawCake(); }Copy the code
update
Add stereo effect, extract configuration parametersCopy the code
<declare-styleable name="CakeSurfaceView">
<attr name="isDrawByAnim" format="boolean"/>// Animate <attr name="isSolid" format="boolean"/>// Whether stereo <attr name="duration" format="integer|reference"<attr name="defaultColor" format="string"/>// Default color <attr name="ringWidth" format="integer|reference"/>// Ring width <attr name="solidWidth" format="integer|reference"<attr name="fineTuningWidth" format="integer|reference"/>// Adjust the width </declare-styleable>
Copy the code
XML is used inCopy the code
<com.xp.xppiechart.view.CakeSurfaceView
android:id="@+id/assets_pie_chart"
android:background="#ffffff"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:defaultColor="#ff8712"
app:ringWidth="20"
app:solidWidth="5"
app:duration="3000"
app:isSolid="true"
app:isDrawByAnim="true"/>
Copy the code
The above is a simple implementation of dynamic drawing pie chart, to be improved, will be updated later. If you have any suggestions or comments, please contact us in time.