1.效果
2.分析如何实现
- 画外弧
- 画内弧
- 画步数
- 提供方法,供使用者调用
3.代码实现
3.1
在values目录下attrs.xml文件中添加自定义属性
3.2 在布局中引用
3.3 创建自定义View类
public class QQStyepView extends View {
public QQStyepView(Context context) {
this(context,null);
}
public QQStyepView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs,0);
}
public QQStyepView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
}
3.4 在自定义View的构造方法中获取自定义属性
//获取自定义的属性
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.QQStyepView);
cmOuterColor = typedArray.getColor(R.styleable.QQStyepView_cmOuterColor,cmOuterColor);
cmInnerColor = typedArray.getColor(R.styleable.QQStyepView_cmInnerColor,cmInnerColor);
cmBorderWidth = typedArray.getDimensionPixelOffset(R.styleable.QQStyepView_cmBorderWidth,cmBorderWidth);
cmStepTextSize = typedArray.getDimensionPixelOffset(R.styleable.QQStyepView_cmStepTextSize,cmStepTextSize);
cmStepTextColor = typedArray.getColor(R.styleable.QQStyepView_cmStepTextColor,cmStepTextColor);
typedArray.recycle();
3.5 重写onMeasure()方法,重新测量控件宽高
如果宽度高度的模式为AT_MOST,则强制指定宽高
/**
* 测量
* @param widthMeasureSpec
* @param heightMeasureSpec
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//获取高度,宽度
int heigth = MeasureSpec.getSize(heightMeasureSpec);
int width = MeasureSpec.getSize(widthMeasureSpec);
//获取高度模式,宽度模式
int heigthMode = MeasureSpec.getMode(heightMeasureSpec);
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
//如果高度的模式与宽度模式都是AT_MOST,则设置默认大小
if(MeasureSpec.AT_MOST == heigthMode){
heigth = 40;
}
if(MeasureSpec.AT_MOST == widthMode){
width = 40;
}
//重新设置自定义View的宽高,并且保证宽高一致
heigth = width>heigth? heigth: width;
width = width>heigth? heigth:width;
setMeasuredDimension(heigth,width);
}
3.6 在自定义View的构造方法中创建画笔
//创建画笔
cmOuterPaint = new Paint();
//设置抗锯齿
cmOuterPaint.setAntiAlias(true);
//设置圆弧宽度
cmOuterPaint.setStrokeWidth(cmBorderWidth);
//设置为Round
cmOuterPaint.setStrokeCap(Paint.Cap.ROUND);
cmOuterPaint.setStrokeJoin(Paint.Join.ROUND);
//设置画笔颜色
cmOuterPaint.setColor(cmOuterColor);
cmOuterPaint.setStyle(Paint.Style.STROKE);
//创建画笔
cmInnerPaint = new Paint();
//设置抗锯齿
cmInnerPaint.setAntiAlias(true);
//设置圆弧宽度
cmInnerPaint.setStrokeWidth(cmBorderWidth);
//设置为Round
cmInnerPaint.setStrokeCap(Paint.Cap.ROUND);
cmInnerPaint.setStrokeJoin(Paint.Join.ROUND);
//设置画笔颜色
cmInnerPaint.setColor(cmInnerColor);
cmInnerPaint.setStyle(Paint.Style.STROKE);
//创建画笔
cmTextPaint = new Paint();
//设置抗锯齿
cmTextPaint.setAntiAlias(true);
//设置为Round
cmTextPaint.setStrokeCap(Paint.Cap.ROUND);
cmTextPaint.setStrokeJoin(Paint.Join.ROUND);
//设置画笔颜色
cmTextPaint.setColor(cmOuterColor);
cmTextPaint.setStyle(Paint.Style.STROKE);
cmTextPaint.setTextSize(cmStepTextSize);
3.7 重写onDray()方法
1.绘外弧,2.绘内弧,3绘步数
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//画外圆圈
RectF rectF = new RectF(cmBorderWidth/2,cmBorderWidth/2,getWidth()-cmBorderWidth/2,getHeight()-cmBorderWidth/2);
canvas.drawArc(rectF,135,270,false,cmOuterPaint);
//画内圆圈 设置画笔颜色
cmInnerPaint.setColor(cmInnerColor);
float sweepAngle = (float)cmStepCurrent / cmStepMax;
canvas.drawArc(rectF,135,sweepAngle*270,false,cmInnerPaint);
//画文字 重置画笔
String cmStep = String.valueOf(cmStepCurrent);
Rect rectBounds = new Rect();
cmTextPaint.getTextBounds(cmStep,0,cmStep.length(),rectBounds);
int dx = getWidth()/2 - rectBounds.width()/2;
//找基线
Paint.FontMetricsInt fontMetricsInt = cmTextPaint.getFontMetricsInt();
int dy = (fontMetricsInt.bottom - fontMetricsInt.top) / 2 - fontMetricsInt.bottom;
int baseLine = getHeight()/2 + dy;
canvas.drawText(cmStep,dx,baseLine,cmTextPaint);
}
3.8 提供方法,供外部使用
/**
* 设置最大步数
* @param maxStep
*/
public synchronized void setMaxStep(int maxStep){
if(0 > maxStep){
throw new IllegalArgumentException("最大步数不能小于0");
}
this.cmStepMax = maxStep;
}
/**
* 获取最大步数
* @return
*/
public synchronized int getMaxStep(){
return cmStepMax;
}
/**
* 设置当前步数
* @param progressStep
*/
public synchronized void setStepProgress(int progressStep){
if(0 > progressStep){
throw new IllegalArgumentException("当前步数不能小于0");
}
this.cmStepCurrent = progressStep;
//重新绘制
invalidate();
}
/**
* 获取当前步数
* @return
*/
public synchronized int getProgressStep(){
return cmStepCurrent;
}
4.调用
cmMainQQStep = (QQStyepView)findViewById(R.id.main_qqstep);
//1.设置最大步数
cmMainQQStep.setMaxStep(4000);
//2.添加属性动画
ValueAnimator valueAnimator = ObjectAnimator.ofFloat(0, 3369);
valueAnimator.setDuration(1000);
valueAnimator.setInterpolator(new DecelerateInterpolator());
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float animatedValue = (float)animation.getAnimatedValue();
cmMainQQStep.setStepProgress((int) animatedValue);
}
});
valueAnimator.start();
Git地址
https://github.com/hualianrensheng/CMViewDemo
引用
https://www.jianshu.com/p/4e0eb9bb09ab