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