先上效果圖
下面上代碼
1.先定義屬性
<resources>
<declare-styleable name="RoundIndicatorView">
<!--圓盤最大值-->
<attr name="maxNum" format="dimension|integer"/>
<!--圓盤起始角度-->
<attr name="startAngle" format="dimension|integer"/>
<!--圓盤掃過的角度-->
<attr name="sweepAngle" format="dimension|integer"/>
</declare-styleable>
</resources>
該view中用到的變量
private int radius;//內圓半徑
private int mWidth;//控件的寬度
private int mHeight;//控件的高度
private Paint paint_1;//內圓畫筆
private Paint paint_2;
private Paint paint_3;
private Paint paint_4;
private Paint paint_5;
private Context context;
private int maxNum;//圓盤最大值
private int startAngle;//圓盤起始角度
private int sweepAngle;//圓盤掃過的角度
private int sweepInWidth;//內圓弧寬度
private int sweepOutWidth;//外圓寬度
private String[] text ={"較差","中等","良好","優秀","極好"};
private int[] indicatorColor = {0xffffffff,0x00ffffff,0x99ffffff,0xffffffff};
private int currentNum = 0;
初始化自定義的屬性及畫筆
/**
* 初始化自定義屬性
* @param attrs
*/
private void initAttrs(AttributeSet attrs){
TypedArray typedArray = context.obtainStyledAttributes(attrs,R.styleable.RoundIndicatorView);
maxNum = typedArray.getInt(R.styleable.RoundIndicatorView_maxNum,500);
startAngle = typedArray.getInt(R.styleable.RoundIndicatorView_startAngle,160);
sweepAngle = typedArray.getInt(R.styleable.RoundIndicatorView_sweepAngle,220);
sweepInWidth = dp2px(8);
sweepOutWidth = dp2px(3);
typedArray.recycle();
}
/**
* 初始化所有畫筆
*/
private void initPaint(){
paint_1 = new Paint(Paint.ANTI_ALIAS_FLAG);
paint_1.setDither(true);
paint_1.setStyle(Paint.Style.STROKE);
paint_1.setColor(0xffffffff);
paint_2 = new Paint(Paint.ANTI_ALIAS_FLAG);
paint_3 = new Paint(Paint.ANTI_ALIAS_FLAG);
paint_4 = new Paint(Paint.ANTI_ALIAS_FLAG);
paint_5 = new Paint(Paint.ANTI_ALIAS_FLAG);
}
重寫onmeasure及ondraw
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int wSize = MeasureSpec.getSize(widthMeasureSpec);
int wMode = MeasureSpec.getMode(widthMeasureSpec);
int hSize = MeasureSpec.getSize(heightMeasureSpec);
int hMode = MeasureSpec.getMode(heightMeasureSpec);
if (wMode == MeasureSpec.EXACTLY ){
mWidth = wSize;
}else {
mWidth = dp2px(300);
}
if (hMode == MeasureSpec.EXACTLY){
mHeight = hSize;
}else {
mHeight = dp2px(400);
}
setMeasuredDimension(mWidth,mHeight);
}
/**
* 注意圓的半徑不要在構造方法裏就去設置,那時候是得不到view的寬高值的,所以我在onDraw方法裏設置半徑,默認就view寬度的1/4吧。把原點移到view的中心去:
* @param canvas
*/
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
radius = getMeasuredWidth()/4;//不要在構造方法裏初始化,那時還沒測量寬高
canvas.save();
canvas.translate(mWidth/2,mWidth/2);
drawRound(canvas);//畫圓盤
drawScale(canvas);//畫刻度及文字
drawIndicator(canvas);//畫芝麻分指示針
drawCenterText(canvas);//畫中間的文字
canvas.restore();
}
畫內外兩個圓
/**
* 畫內外圓
* @param canvas
*/
private void drawRound(Canvas canvas){
canvas.save();
//內圓
paint_1.setAlpha(0x40);
paint_1.setStrokeWidth(sweepInWidth);
RectF rectF = new RectF(-radius,-radius,radius,radius);
canvas.drawArc(rectF,startAngle,sweepAngle,false,paint_1);
//外圓
paint_1.setStrokeWidth(sweepOutWidth);
int w = dp2px(10);
RectF rectF1 = new RectF(-radius-w,-radius-w,radius+w,radius+w);
canvas.drawArc(rectF1,startAngle,sweepAngle,false,paint_1);
canvas.restore();
}
畫刻度以及刻度值
/**
* 畫刻度及刻度值
* @param canvas
*/
private void drawScale(Canvas canvas){
canvas.save();
float angle = sweepAngle/30;//刻度間隔
canvas.rotate(-270 + startAngle);//將起始的刻度點旋轉到正上方
for (int i = 0; i <= 30; i++) {
if (i%6 == 0){//畫粗刻度和刻度值
paint_1.setStrokeWidth(dp2px(2));
paint_1.setAlpha(0x70);
canvas.drawLine(0,-radius-sweepInWidth/2,0,-radius+sweepInWidth/2+dp2px(1),paint_1);
drawText(canvas,i*maxNum/30+"",paint_1);
}else {//畫西刻度
paint_1.setStrokeWidth(dp2px(1));
paint_1.setAlpha(0x55);
canvas.drawLine(0,-radius-sweepInWidth/2,0,-radius+sweepInWidth/2,paint_1);
}
if (i==3 || i==9 || i==15 || i==21 || i==27){
paint_1.setStrokeWidth(dp2px(2));
paint_1.setAlpha(0x55);
drawText(canvas,text[0],paint_1);
}
canvas.rotate(angle);//逆時針
}
canvas.restore();
}
private void drawText(Canvas canvas,String text,Paint paint){
paint.setStyle(Paint.Style.FILL);
paint.setTextSize(sp2px(8));
float width = paint.measureText(text);//相比getTextBounds來說,這個方法獲得的類型是float,更精確些
// Rect rect = new Rect();
//paint.getTextBounds(text,0,text.length(),rect);
canvas.drawText(text,-width/2,-radius+dp2px(15),paint);
paint.setStyle(Paint.Style.STROKE);
}
畫芝麻分的指示針
/**
* 畫芝麻分指示針
* @param c
*/
private void drawIndicator(Canvas c){
c.save();
paint_2.setStyle(Paint.Style.STROKE);
int sweep;
if (currentNum <=maxNum){
// sweep = currentNum/maxNum*sweepAngle;
sweep = (int)((float)currentNum/(float)maxNum*sweepAngle);
}else {
sweep = sweepAngle;
}
paint_2.setStrokeWidth(sweepOutWidth);
Shader shader = new SweepGradient(0,0,indicatorColor,null);
paint_2.setShader(shader);
int w = dp2px(10);
RectF rectF = new RectF(-radius-w,-radius-w,radius+w,radius+w);
c.drawArc(rectF,startAngle,sweep,false,paint_2);
float x = (float) ((radius+dp2px(10))*Math.cos(Math.toRadians(startAngle+sweep)));
float y = (float) ((radius+dp2px(10))*Math.sin(Math.toRadians(startAngle+sweep)));
paint_3.setStyle(Paint.Style.FILL);
paint_3.setColor(0xffffffff);
paint_3.setMaskFilter(new BlurMaskFilter(dp2px(3), BlurMaskFilter.Blur.SOLID));//需關閉硬件加速
c.drawCircle(x,y,dp2px(3),paint_3);
c.restore();
}
畫中間的文字
private void drawCenterText(Canvas canvas){
canvas.save();
paint_4.setStyle(Paint.Style.FILL);
paint_4.setTextSize(radius/2);
paint_4.setColor(0xffffffff);
canvas.drawText(currentNum+"",-paint_4.measureText(currentNum+"")/2,0,paint_4);
paint_4.setTextSize(radius/4);
String content = "信用";
if (currentNum<maxNum/5){
content += text[0];
}else if (currentNum>=maxNum/5 && currentNum <maxNum*2/5){
content += text[1];
}else if (currentNum>=maxNum*2/5 && currentNum < maxNum*3/5){
content += text[2];
}else if (currentNum>= maxNum*3/5 && currentNum < maxNum*4/5){
content += text[3];
}else if (currentNum>=maxNum*4/5){
content += text[4];
}
Rect rect = new Rect();
paint_4.getTextBounds(content,0,content.length(),rect);
canvas.drawText(content,-rect.width()/2,rect.height()+20,paint_4);
canvas.restore();
}
寫一個設置及獲取當前值的方法以及改變值後的動畫
//獲取當前值
public int getCurrentNum() {
return currentNum;
}
//設置當前值
public void setCurrentNum(int currentNum) {
this.currentNum = currentNum;
invalidate();
}
//設置改變值後的動畫
public void setCurrentNumAnim(int num) {
float duration = (float)Math.abs(num-currentNum)/maxNum *1500+500; //根據進度差計算動畫時間
ObjectAnimator anim = ObjectAnimator.ofInt(this,"currentNum",num);
anim.setDuration((long) Math.min(duration,2000));
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int value = (int) animation.getAnimatedValue();
int color = calculateColor(value);
setBackgroundColor(color);
}
});
anim.start();
}
private int calculateColor(int value){
ArgbEvaluator evealuator = new ArgbEvaluator();
float fraction = 0;
int color = 0;
if(value <= maxNum/2){
fraction = (float)value/(maxNum/2);
color = (int) evealuator.evaluate(fraction,0xFFFF6347,0xFFFF8C00); //由紅到橙
}else {
fraction = ( (float)value-maxNum/2 ) / (maxNum/2);
color = (int) evealuator.evaluate(fraction,0xFFFF8C00,0xFF00CED1); //由橙到藍
}
return color;
}
該自定義view中用到的方法
//該view用到的工具類
protected int dp2px(int dp){
return (int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
dp,
getResources().getDisplayMetrics()
);
}
protected int sp2px(int sp){
return (int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_SP,
sp,
getResources().getDisplayMetrics()
);
}
public static DisplayMetrics getScreenMetrics(Context context){
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics dm = new DisplayMetrics();
wm.getDefaultDisplay().getMetrics(dm);
return dm;
}
源碼下載地址
http://download.csdn.net/detail/zhou_anzhuojinjie/9738937