本文由陈朝勇原创。
陈朝勇的博客地址:
http://blog.csdn.net/ccy0122
本篇文章是我的一个算是做注释的一个博客,废话不多说,开始我们的神器开发.
首先看下我们的效果图,
package cn.yuan.yu.mainmodule.module;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
/**
* Created by yukoyuan on 2016/11/30.
* 这是一个仿制芝麻积分的自定义控件
*/
public class RoundIndicatorView extends View {
public RoundIndicatorView(Context context) {
this(context, null);
}
public RoundIndicatorView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public RoundIndicatorView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.context = context;
setBackgroundColor(0xFFFF6347);
/**
* 初始化属性
*/
initAttr(attrs);
/**
* 初始化画笔
*/
initPaint();
}
}
<declare-styleable name="RoundIndicatorView">
<attr name="maxNum" format="integer" />
<attr name="startAngle" format="integer" />
<attr name="sweepAngle" format="integer" />
declare-styleable>
/**
* 活得各项参数合集
*/
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.RoundIndicatorView);
/**
* 最大的值
*/
maxNum = array.getInt(R.styleable.RoundIndicatorView_maxNum, 900);
/**
* 开始的角度
*/
startAngle = array.getInt(R.styleable.RoundIndicatorView_startAngle, 160);
/**
* 扫过的角度
*/
sweepAngle = array.getInt(R.styleable.RoundIndicatorView_sweepAngle, 220);
/**
* 内部圆的宽度
*/
sweepInWidth = dp2px(8);
/**
* 外部圆的宽度
*/
sweepOutWidth = dp2px(3);
/**
* 释放资源
*/
array.recycle();
/**
* 这是一个初始化画笔的方法
*/
private void initPaint() {
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setDither(true);
paint.setStyle(Paint.Style.STROKE);
paint.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);
}
/**
* 自定义控件第二个要走的方法
*
* measure操作主要用于计算视图的大小,即视图的宽度和长度。在view中定义为final类型,要求子类不能修改。
*
* 子类可以覆写onMeasure()方法实现自己的计算视图大小的方式,并通过setMeasuredDimension(width, height)保存计算结果。
*
* @param widthMeasureSpec 宽度
* @param heightMeasureSpec 高度
*/
@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);
/**
* 对于不是确定值的直接给定300*400的大小
*/
if (wMode == MeasureSpec.EXACTLY) {
mWidth = wSize;
} else {
mWidth = dp2px(300);
}
if (hMode == MeasureSpec.EXACTLY) {
mHeight = hSize;
} else {
mHeight = dp2px(400);
}
/**
* 保存计算结果
*/
setMeasuredDimension(mWidth, mHeight);
}
/**
* 自定义控件第五个要走的方法
*
* @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();
//内圆
//设置一下它的透明度,范围是00~ff。
paint.setAlpha(0x40);
paint.setStrokeWidth(sweepInWidth);
RectF rectf = new RectF(-radius, -radius, radius, radius);
canvas.drawArc(rectf, startAngle, sweepAngle, false, paint);
//外圆
paint.setStrokeWidth(sweepOutWidth);
int w = dp2px(10);
RectF rectf2 = new RectF(-radius - w, -radius - w, radius + w, radius + w);
canvas.drawArc(rectf2, startAngle, sweepAngle, false, paint);
canvas.restore();
}
/**
* 这是一个画刻度的方法
*
* @param canvas 画布
*/
private void drawScale(Canvas canvas) {
canvas.save();
float angle = (float) sweepAngle / 30;//刻度间隔
canvas.rotate(-270 + startAngle); //将起始刻度点旋转到正上方(270)
for (int i = 0; i <= 30; i++) {
if (i % 6 == 0) { //画粗刻度和刻度值
paint.setStrokeWidth(dp2px(2));
paint.setAlpha(0x70);
canvas.drawLine(0, -radius - sweepInWidth / 2, 0, -radius + sweepInWidth / 2 + dp2px(1), paint);
drawText(canvas, i * maxNum / 30 + "", paint);
} else { //画细刻度
paint.setStrokeWidth(dp2px(1));
paint.setAlpha(0x50);
canvas.drawLine(0, -radius - sweepInWidth / 2, 0, -radius + sweepInWidth / 2, paint);
}
if (i == 3 || i == 9 || i == 15 || i == 21 || i == 27) { //画刻度区间文字
paint.setStrokeWidth(dp2px(2));
paint.setAlpha(0x50);
drawText(canvas, text[(i - 3) / 6], paint);
}
canvas.rotate(angle); //逆时针
}
canvas.restore();
}
/**
* 这是一个画字体的方法
*
* @param canvas 画布
* @param text 文字
* @param paint 画笔
*/
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,更精确些
canvas.drawText(text, -width / 2, -radius + dp2px(15), paint);
paint.setStyle(Paint.Style.STROKE);
}
/**
* 绘制当前进度值
*
* @param canvas
*/
private void drawIndicator(Canvas canvas) {
canvas.save();
/**
*
*/
paint_2.setStyle(Paint.Style.STROKE);
int sweep;
if (currentNum <= maxNum) {
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);
canvas.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)); //需关闭硬件加速
canvas.drawCircle(x, y, dp2px(3), paint_3);
canvas.restore();
}
/**
* 绘制控件中间的文字
*
* @param canvas 画布
*/
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 * 1 / 5) {
content += text[0];
} else if (currentNum >= maxNum * 1 / 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 r = new Rect();
paint_4.getTextBounds(content, 0, content.length(), r);
canvas.drawText(content, -r.width() / 2, r.height() + 20, paint_4);
canvas.restore();
}
/**
* 设置选择数字之后的动画效果
*
* @param num
*/
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();
}
/**
* 选择颜色
*
* @param value
* @return
*/
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;
}
ok,到此我们的自定义芝麻积分就到此完成了.感谢大家.