Android View 提升 十 之 自定义View
1. 圆盘 效果:

public class MyProgressView extends View {
private RectF mWheelRect = new RectF();
private RectF mSmallRect = new RectF();
private Paint mSmallPaint;
private float mSmallStrokeWidth;
private Paint mDefaultWheelPaint;
private Paint mFinishWheelPaint;
private Paint mCenterWheelPaint;
private Paint mTitlePaint, mStepPaint, mTargetPaint;
private float mCircleStrokeWidth;
private float mSweepAnglePer;
private float mPercent;
private int mStepNum, mCurrStepNum;
private BarAnimation mAnim;
private int mMaxStepNum;
private float mTitleY, mStepY, mTargetY;
private DecimalFormat mDecimalFormat = new DecimalFormat("#.0");
private static String PERCENT;
public MyProgressView(Context context){
super(context);
init(null,0);
}
public MyProgressView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init(attrs,0);
}
public MyProgressView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(attrs,defStyleAttr);
}
private void init(AttributeSet attrs, int defStyle){
mFinishWheelPaint = new Paint();
mFinishWheelPaint.setColor(Color.rgb(100,113,205));
mFinishWheelPaint.setStyle(Paint.Style.STROKE);
mFinishWheelPaint.setStrokeCap(Paint.Cap.ROUND);
mFinishWheelPaint.setAntiAlias(true);
mCenterWheelPaint = new Paint();
mCenterWheelPaint.setColor(Color.rgb(0, 0, 243));
mCenterWheelPaint.setStyle(Paint.Style.STROKE);
mCenterWheelPaint.setStrokeCap(Paint.Cap.ROUND);
mCenterWheelPaint.setAntiAlias(true);
mDefaultWheelPaint = new Paint();
mDefaultWheelPaint.setColor(Color.rgb(255, 0, 0));
mDefaultWheelPaint.setStyle(Paint.Style.STROKE);
mDefaultWheelPaint.setStrokeCap(Paint.Cap.ROUND);
mDefaultWheelPaint.setAntiAlias(true);
mTitlePaint = new Paint();
mTitlePaint.setAntiAlias(true);
mTitlePaint.setColor(Color.WHITE);
mStepPaint = new Paint();
mStepPaint.setAntiAlias(true);
mStepPaint.setColor(Color.WHITE);
mTargetPaint = new Paint();
mTargetPaint.setAntiAlias(true);
mTargetPaint.setColor(Color.WHITE);
mAnim = new BarAnimation();
mSmallPaint = new Paint();
mSmallPaint.setAntiAlias(true);
mSmallPaint.setStyle(Paint.Style.STROKE);
mSmallPaint.setStrokeCap(Paint.Cap.SQUARE);
mSmallPaint.setColor(Color.CYAN);
}
private double startX;
private double startY;
private float stopX;
private float stopY;
@Override
protected void onDraw(Canvas canvas) {
canvas.drawArc(mWheelRect, 0, 179,false, mDefaultWheelPaint);
canvas.drawArc(mWheelRect, 180, 180, false, mCenterWheelPaint);
canvas.drawArc(mWheelRect, 0, mSweepAnglePer, false, mFinishWheelPaint);
canvas.drawLine((float) startX, (float) startY,stopX,stopY,mSmallPaint);
canvas.drawArc(mSmallRect, 0, 359,false,mSmallPaint);
}
private float mBigRadius;
private float mSmallRadius;
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int height = getDefaultSize(getSuggestedMinimumHeight(),heightMeasureSpec);
int width = getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec);
int min = Math.min(width, height);
setMeasuredDimension(min, min);
mCircleStrokeWidth = getTextScale(15, min);
float pressExtraStrokeWidth = getTextScale(10, min);
mWheelRect.set(mCircleStrokeWidth + pressExtraStrokeWidth, mCircleStrokeWidth + pressExtraStrokeWidth,
min - mCircleStrokeWidth - pressExtraStrokeWidth, min - mCircleStrokeWidth - pressExtraStrokeWidth);
mSmallStrokeWidth = getTextScale(15,min);
float mSpace = getTextScale(150,min);
float mSmallExtraStrokeWidth = mSpace+mCircleStrokeWidth+pressExtraStrokeWidth;
mSmallRect.set(mSmallExtraStrokeWidth+mSmallStrokeWidth,
mSmallExtraStrokeWidth+mSmallStrokeWidth,
min-mSmallStrokeWidth-mSmallExtraStrokeWidth,
min-mSmallStrokeWidth-mSmallExtraStrokeWidth);
mSmallPaint.setStrokeWidth(mSmallStrokeWidth);
mBigRadius = mWheelRect.centerX()-mCircleStrokeWidth-pressExtraStrokeWidth-mCircleStrokeWidth;
mSmallRadius = mSmallRect.centerX()-mSmallExtraStrokeWidth-mSmallStrokeWidth;
startX = mWheelRect.centerX()+mBigRadius;
startY = mWheelRect.centerY();
stopX = mSmallRect.centerX()+mSmallRadius;
stopY = mSmallRect.centerY();
mTitlePaint.setTextSize(getTextScale(60, min));
mStepPaint.setTextSize(getTextScale(120, min));
mTargetPaint.setTextSize(getTextScale(40, min));
mTitleY = getTextScale(170, min);
mStepY = getTextScale(300, min);
mTargetY = getTextScale(380, min);
mFinishWheelPaint.setStrokeWidth(mCircleStrokeWidth);
mCenterWheelPaint.setStrokeWidth(mCircleStrokeWidth);
mDefaultWheelPaint.setStrokeWidth(mCircleStrokeWidth - getTextScale(2, min));
mDefaultWheelPaint.setShadowLayer(getTextScale(10, min), 0, 0, Color.rgb(127, 127, 127));
}
public class BarAnimation extends Animation {
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
mPercent = Float.parseFloat(mDecimalFormat.format(interpolatedTime * mStepNum * 100f / mMaxStepNum));
mSweepAnglePer = interpolatedTime * mStepNum * 360 / mMaxStepNum;
mCurrStepNum = (int) (interpolatedTime * mStepNum);
startX = mWheelRect.centerX()+(mBigRadius*(Math.cos(mSweepAnglePer/180*Math.PI)));
startY = mWheelRect.centerY()+(mBigRadius*(Math.sin(mSweepAnglePer/180*Math.PI)));
stopX = (float) (mSmallRect.centerX()+(mSmallRadius*(Math.cos(mSweepAnglePer/180*Math.PI))));
stopY = (float) (mSmallRect.centerY()+(mSmallRadius*(Math.sin(mSweepAnglePer/180*Math.PI))));
requestLayout();
}
}
public float getPercent() {
return mPercent;
}
public float getTextScale(float n, float m) {
return n / 500 * m;
}
public void update(int stepCount, int time) {
this.mStepNum = stepCount;
mAnim.setDuration(time);
setAnimationTime(time);
this.startAnimation(mAnim);
}
public void setMaxStepNum(int stepNum) {
mMaxStepNum = stepNum;
}
public void setColor(int color) {
mFinishWheelPaint.setColor(color);
mStepPaint.setColor(color);
}
public void setAnimationTime(int time) {
mAnim.setDuration(time * mStepNum / mMaxStepNum);
}
}
2. 条形图 效果:

public class MyProgressView extends View {
private RectF mWheelRect = new RectF();
private RectF mSmallRect = new RectF();
private Paint mSmallPaint;
private float mSmallStrokeWidth;
private Paint mDefaultWheelPaint;
private Paint mFinishWheelPaint;
private Paint mCenterWheelPaint;
private Paint mTitlePaint, mStepPaint, mTargetPaint;
private float mCircleStrokeWidth;
private float mSweepAnglePer;
private float mPercent=0f;
private int mStepNum, mCurrStepNum;
private BarAnimation mAnim;
private int mMaxStepNum;
private float mTitleY, mStepY, mTargetY;
private DecimalFormat mDecimalFormat = new DecimalFormat("#.0");
private static String PERCENT;
public MyProgressView(Context context){
super(context);
init(null,0);
}
public MyProgressView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init(attrs,0);
}
public MyProgressView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(attrs,defStyleAttr);
}
private void init(AttributeSet attrs, int defStyle){
mFinishWheelPaint = new Paint();
mFinishWheelPaint.setColor(Color.rgb(100,113,205));
mFinishWheelPaint.setStyle(Paint.Style.STROKE);
mFinishWheelPaint.setStrokeCap(Paint.Cap.ROUND);
mFinishWheelPaint.setAntiAlias(true);
mCenterWheelPaint = new Paint();
mCenterWheelPaint.setColor(Color.rgb(0, 0, 243));
mCenterWheelPaint.setStyle(Paint.Style.STROKE);
mCenterWheelPaint.setStrokeCap(Paint.Cap.ROUND);
mCenterWheelPaint.setAntiAlias(true);
mDefaultWheelPaint = new Paint();
mDefaultWheelPaint.setColor(Color.rgb(255, 0, 0));
mDefaultWheelPaint.setStyle(Paint.Style.STROKE);
mDefaultWheelPaint.setStrokeCap(Paint.Cap.ROUND);
mDefaultWheelPaint.setAntiAlias(true);
mTitlePaint = new Paint();
mTitlePaint.setAntiAlias(true);
mTitlePaint.setColor(Color.WHITE);
mStepPaint = new Paint();
mStepPaint.setAntiAlias(true);
mStepPaint.setColor(Color.WHITE);
mTargetPaint = new Paint();
mTargetPaint.setAntiAlias(true);
mTargetPaint.setColor(Color.RED);
mAnim = new BarAnimation();
mSmallPaint = new Paint();
mSmallPaint.setAntiAlias(true);
mSmallPaint.setStyle(Paint.Style.STROKE);
mSmallPaint.setStrokeCap(Paint.Cap.SQUARE);
mSmallPaint.setColor(Color.CYAN);
}
private int[] array = {3,5,7};
@Override
protected void onDraw(Canvas canvas) {
drawPos(canvas);
float tmp = center_x+mPointSpace;;
int i = 0;
while(i<array.length){
canvas.drawLine(tmp,X_startY,tmp, X_startY-(getTextScale(array[i]*mPercent,xmin)),mStepPaint);
i++;
tmp=tmp+mPointSpace;
}
}
float xmin;
private void drawPos(Canvas canvas){
canvas.drawLine(X_startX,X_startY,X_stopX,X_stopY,mSmallPaint);
canvas.drawLine(X_stopX,X_stopY,X_stopX-mArcSpace,X_stopY+mArcSpace,mSmallPaint);
canvas.drawLine(X_stopX,X_stopY,X_stopX-mArcSpace,X_stopY-mArcSpace,mSmallPaint);
canvas.drawLine(Y_startX,Y_startY,Y_stopX,Y_stopY,mSmallPaint);
canvas.drawLine(Y_stopX,Y_stopY,Y_stopX-mArcSpace,Y_stopY+mArcSpace,mSmallPaint);
canvas.drawLine(Y_stopX,Y_stopY,Y_stopX+mArcSpace,Y_stopY+mArcSpace,mSmallPaint);
float tmp = center_x;
int i = 0;
while(tmp<=X_stopX){
if(i==0){
i++;
tmp=tmp+mPointSpace;
continue;
}
canvas.drawLine(tmp,X_startY,tmp-mPointLine, X_startY,mTargetPaint);
String msg=""+i+"";
canvas.drawText(msg,tmp-mTargetPaint.measureText(msg)*4/5,X_startY+mTextSpace,mTargetPaint);
i++;
tmp=tmp+mPointSpace;
}
i=0;
tmp = center_x;
while(tmp>=X_startX){
if(i==0){
i--;
tmp=tmp-mPointSpace;
continue;
}
canvas.drawLine(tmp,X_startY,tmp-mPointLine, X_startY,mTargetPaint);
String msg=""+i+"";
canvas.drawText(msg,tmp-mTargetPaint.measureText(msg)*4/5,X_startY+mTextSpace,mTargetPaint);
i--;
tmp=tmp-mPointSpace;
}
i=0;
tmp = center_y;
while(tmp>=Y_stopY){
canvas.drawLine(Y_startX,tmp,Y_startX,tmp-mPointLine,mTargetPaint);
String msg=""+i+"";
canvas.drawText(msg,Y_startX-mTextSpace,tmp+mTargetPaint.measureText(msg)*5/3,mTargetPaint);
i++;
tmp=tmp-mPointSpace;
}
i=-1;
tmp = center_y+mPointSpace;
while(tmp<=Y_startY){
canvas.drawLine(Y_startX,tmp,Y_startX,tmp-mPointLine,mTargetPaint);
String msg=""+i+"";
canvas.drawText(msg,Y_startX-mTextSpace,tmp+mTargetPaint.measureText(msg)*2/3,mTargetPaint);
i--;
tmp=tmp+mPointSpace;
}
}
private float X_startX;
private float X_startY;
private float Y_startX;
private float Y_startY;
private float X_stopX;
private float X_stopY;
private float Y_stopX;
private float Y_stopY;
private float mArcSpace;
private float mTextSpace;
private float mPointSpace;
private float mPointLine;
private float center_x;
private float center_y;
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int height = getDefaultSize(getSuggestedMinimumHeight(),heightMeasureSpec);
int width = getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec);
int min = Math.min(width, height);
xmin = min;
setMeasuredDimension(min, min);
float space = getTextScale(15,min);
X_startX = space;
X_startY = min-space*6;
X_stopX = min-space;
X_stopY = min-space*6;
Y_startX = space*6;
Y_startY = min-space;
Y_stopX = space*6;
Y_stopY = space;
center_x = Y_startX;
center_y = X_stopY;
mArcSpace = getTextScale(10,min);
mSmallPaint.setStrokeWidth(3*min/500);
mTargetPaint.setTextSize(getTextScale(30,min));
mTargetPaint.setStrokeWidth(4*min/500);
mStepPaint.setStrokeWidth(10*min/500);
mTextSpace = getTextScale(30,min);
mPointSpace = getTextScale(50,min);
mPointLine = getTextScale(5,min);
}
public class BarAnimation extends Animation {
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
mPercent = Float.parseFloat(mDecimalFormat.format(interpolatedTime * mStepNum * 100f / mMaxStepNum));
requestLayout();
}
}
public float getPercent() {
return mPercent;
}
public float getTextScale(float n, float m) {
return n / 500 * m;
}
public void update(int stepCount, int time) {
this.mStepNum = stepCount;
mAnim.setDuration(time);
setAnimationTime(time);
this.startAnimation(mAnim);
}
public void setMaxStepNum(int stepNum) {
mMaxStepNum = stepNum;
}
public void setColor(int color) {
mFinishWheelPaint.setColor(color);
mStepPaint.setColor(color);
}
public void setAnimationTime(int time) {
mAnim.setDuration(time * mStepNum / mMaxStepNum);
}
}