效果图如下:
属性文件如下:
attrs_pie_view.xml
<resources>
<declare-styleable name="PieView">
<attr name="color_a" format="color" />
<attr name="color_b" format="color" />
<attr name="color_c" format="color" />
<attr name="color_d" format="color" />
<attr name="stroke_width" format="dimension" />
<attr name="text_color" format="color" />
<attr name="text_size" format="dimension" />
<attr name="text" format="string" />
<attr name="percent_arc_a" format="float" />
<attr name="text_percent_size" format="dimension" />
</declare-styleable>
</resources>
代码文件如下:
PieView.java
package net.sytm.pieview;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
import android.view.animation.LinearInterpolator;
public class PieView extends View {
//正常颜色
private int colorA;
//迟到颜色
private int colorB;
//早退颜色
private int colorC;
//未打卡颜色
private int colorD;
//扫过的角度
private float arcA;
private float arcB;
private float arcC;
private float arcD;
//画笔宽度
private int strokeWidth;
//文字颜色
private int textColor;
//文字大小
private int textSize;
//直径
private int diameter;
//画笔
private Paint paint;
private TextPaint textPaint;
//扇形区域
private RectF rectF;
//零时变量
private float tmpArcA;
private float tmpArcB;
private float tmpArcC;
private float tmpArcD;
//文字区域
private Rect rect;
//中间百分数
private String text;
//文字区域
private Rect rectPercent;
//百分号%
private String textPercent;
//百分号大小
private int textPercentSize;
//提示文字
private String textTips;
public PieView(Context context) {
this(context, null);
}
public PieView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public PieView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.PieView, defStyle, 0);
int count = array.getIndexCount();
for (int i = 0; i < count; i++) {
int attr = array.getIndex(i);
switch (attr) {
case R.styleable.PieView_color_a:
colorA = array.getColor(attr, Color.WHITE);
break;
case R.styleable.PieView_color_b:
colorB = array.getColor(attr, Color.WHITE);
break;
case R.styleable.PieView_color_c:
colorC = array.getColor(attr, Color.WHITE);
break;
case R.styleable.PieView_color_d:
colorD = array.getColor(attr, Color.WHITE);
break;
case R.styleable.PieView_stroke_width:
strokeWidth = array.getDimensionPixelSize(attr,
(int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 16, getResources().getDisplayMetrics()));
break;
case R.styleable.PieView_text_color:
textColor = array.getColor(attr, Color.WHITE);
break;
case R.styleable.PieView_text_size:
textSize = array.getDimensionPixelSize(attr,
(int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 16, getResources().getDisplayMetrics()));
break;
case R.styleable.PieView_text:
text = array.getString(attr);
break;
case R.styleable.PieView_percent_arc_a:
//这个属性是只是为了预览视图
tmpArcA = percentToDegree(array.getFloat(attr, 0f));
break;
case R.styleable.PieView_text_percent_size:
textPercentSize = array.getDimensionPixelSize(attr,
(int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 16, getResources().getDisplayMetrics()));
break;
}
}
array.recycle();
paint = new Paint();
paint.setAntiAlias(true);
//直径取屏幕的一半
diameter = getResources().getDisplayMetrics().widthPixels / 2;
//半径
int radius = diameter / 2;
rectF = new RectF(- radius , - radius , radius, radius);
rectPercent = new Rect();
textPaint = new TextPaint();
textPaint.setAntiAlias(true);
rect = new Rect();
textPercent = "%";
textTips = "优秀度";
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthNode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightNode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int width;
int height;
if (widthNode == MeasureSpec.EXACTLY) {
width = widthSize;
}
else {
width = diameter * 2;
}
if (heightNode == MeasureSpec.EXACTLY) {
height = heightSize;
}
else {
height = diameter * 2 - diameter / 2;
}
setMeasuredDimension(width, height);
}
@Override
protected void onDraw(Canvas canvas) {
initCanvas(canvas);
drawArcA(canvas);
drawArcB(canvas);
drawArcC(canvas);
drawArcD(canvas);
drawText(canvas);
}
/**
* 初始化画板
* 移动画板的坐标原点
* 目的为了后面绘制方便,更符合人类的思维模式
* @param canvas
*/
private void initCanvas(Canvas canvas) {
canvas.translate(getWidth() / 2, getHeight() / 2);
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.RED);
//原点
if (BuildConfig.DEBUG) {
canvas.drawCircle(0, 0, 3, paint);
}
}
/**
* 绘制正常数据
* @param canvas
*/
private void drawArcA(Canvas canvas) {
paint.setStyle(Paint.Style.STROKE);
paint.setColor(colorA);
paint.setStrokeWidth(strokeWidth);
canvas.drawArc(rectF, 0, tmpArcA, false, paint);
}
/**
* 绘制迟到数据
* @param canvas
*/
private void drawArcB(Canvas canvas) {
paint.setStyle(Paint.Style.STROKE);
paint.setColor(colorB);
paint.setStrokeWidth(strokeWidth);
canvas.drawArc(rectF, arcA, tmpArcB, false, paint);
}
/**
* 绘制早退数据
* @param canvas
*/
private void drawArcC(Canvas canvas) {
paint.setStyle(Paint.Style.STROKE);
paint.setColor(colorC);
paint.setStrokeWidth(strokeWidth);
canvas.drawArc(rectF, arcA + arcB, tmpArcC, false, paint);
}
/**
* 绘制未打卡数据
* @param canvas
*/
private void drawArcD(Canvas canvas) {
paint.setStyle(Paint.Style.STROKE);
paint.setColor(colorD);
paint.setStrokeWidth(strokeWidth);
canvas.drawArc(rectF, arcA + arcB + arcC, tmpArcD, false, paint);
}
/**
* 绘制文字
* @param canvas
*/
private void drawText(Canvas canvas) {
textPaint.setColor(textColor);
textPaint.setTextSize(textSize);
textPaint.getTextBounds(text, 0, text.length(), rect);
canvas.drawText(text, 0 - rect.width() / 1.5f, rect.height() / 4 , textPaint);
//绘制百分号
textPaint.setTextSize(textPercentSize);
textPaint.getTextBounds(textPercent, 0, textPercent.length(), rectPercent);
canvas.drawText(textPercent, rect.width() / 4 + rectPercent.width(), rect.height() / 10 + rectPercent.height() / 3, textPaint);
//绘制优秀度
textPaint.setColor(Color.parseColor("#999999"));
textPaint.setTextSize(textPercentSize);
textPaint.getTextBounds(textTips, 0, textTips.length(), rectPercent);
canvas.drawText(textTips, - rectPercent.width() / 2, rect.height() + rectPercent.height(), textPaint);
}
/**
* 百分比转换为度数
* @param percent
* @return
*/
private float percentToDegree(float percent) {
return 360 * percent / 100;
}
public void setArcA(float percent) {
this.arcA = percentToDegree(percent);
}
public void setArcB(float percent) {
this.arcB = percentToDegree(percent);
}
public void setArcC(float percent) {
this.arcC = percentToDegree(percent);
}
public void setArcD(float percent) {
this.arcD = percentToDegree(percent);
}
public void setText(String text) {
this.text = text;
}
public void startAnim() {
ValueAnimator valueAnimatorA = ValueAnimator.ofFloat(0f, arcA);
valueAnimatorA.setInterpolator(new LinearInterpolator());
valueAnimatorA.setDuration(1000);
valueAnimatorA.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
tmpArcA = (float) animation.getAnimatedValue();
invalidate();
}
});
valueAnimatorA.start();
ValueAnimator valueAnimatorB = ValueAnimator.ofFloat(0f, arcB);
valueAnimatorB.setInterpolator(new LinearInterpolator());
valueAnimatorB.setDuration(1000);
valueAnimatorB.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
tmpArcB = (float) animation.getAnimatedValue();
invalidate();
}
});
valueAnimatorB.start();
ValueAnimator valueAnimatorC = ValueAnimator.ofFloat(0f, arcC);
valueAnimatorC.setInterpolator(new LinearInterpolator());
valueAnimatorC.setDuration(1000);
valueAnimatorC.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
tmpArcC = (float) animation.getAnimatedValue();
invalidate();
}
});
valueAnimatorC.start();
ValueAnimator valueAnimatorD = ValueAnimator.ofFloat(0f, arcD);
valueAnimatorD.setInterpolator(new LinearInterpolator());
valueAnimatorD.setDuration(1000);
valueAnimatorD.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
tmpArcD = (float) animation.getAnimatedValue();
invalidate();
}
});
valueAnimatorD.start();
}
}
使用步骤如下:
布局引用视图:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<net.sytm.pieview.PieView
android:layout_width="368dp"
android:layout_height="wrap_content"
android:id="@+id/pie_view"
app:color_a="#d2f6f2"
app:color_b="#fe8081"
app:color_c="#ffdf6e"
app:color_d="#afa9ff"
app:stroke_width="32dp"
app:text="70"
app:text_size="64sp"
app:text_color="#333333"
app:percent_arc_a="100"
app:text_percent_size="14sp" />
</LinearLayout>
示例代码:
package net.sytm.pieview;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
PieView pieView = (PieView) findViewById(R.id.pie_view);
//赋值百分比
pieView.setArcA(70);
//赋值百分比
pieView.setArcB(15);
//赋值百分比
pieView.setArcC(10);
//赋值百分比
pieView.setArcD(5);
//中间的百分数
pieView.setText("70");
pieView.startAnim();
}
}
项目源码下载:http://download.csdn.net/detail/hu285279904/9774936