1. 思路分析
自定义View步骤:
1>:values__attrs.xml,自定义属性;
2>:在第三个构造方法中,获取自定义属性;
3>:onMeasure:不是非必须的,测量控件大小;
4>:onDraw:所有绘制代码都写在onDraw方法中;
思路分析
1>:自定义属性:内圆颜色、外圆颜色、圆弧宽度、中间文字颜色、文字大小;
2>:自定义ProgressBar,继承View;
2. 效果图如下
3. 代码如下
1>:attrs.xml
2>:ProgressBar
/**
* ================================================
* Email: [email protected]
* Created by Novate 2018/12/29 15:25
* Version 1.0
* Params:
* Description: 圆形进度条
* ================================================
*/
public class ProgressBar extends View {
// 内圆弧默认颜色
private int mInnerBackground = Color.RED ;
// 外圆弧默认颜色
private int mOuterBackground = Color.RED;
// 圆弧宽度
private int mRoundWidth = 10 ;
// 文字大小
private float mProgressTextSize = 15 ;
// 文字颜色
private int mProgressTextColor = Color.RED;
// 3个画笔 内圆弧画笔、外圆弧画笔、文字画笔
private Paint mInnerPaint,mOuterPaint,mTextPaint;
// 设置最大进度
private int mMax = 100 ;
// 当前进度
private int mProgress = 0 ;
// 百分比
private float persent ;
public ProgressBar(Context context) {
this(context,null);
}
public ProgressBar(Context context, @Nullable AttributeSet attrs) {
this(context, attrs,0);
}
public ProgressBar(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
// 获取自定义属性
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.ProgressBar);
// 内圆弧背景
mInnerBackground = typedArray.getColor(R.styleable.ProgressBar_innerBackground,mInnerBackground);
// 外圆弧背景
mOuterBackground = typedArray.getColor(R.styleable.ProgressBar_outterBackground,mOuterBackground);
// 圆弧宽度
mRoundWidth = typedArray.getDimensionPixelSize(R.styleable.ProgressBar_roundWidth,(int)dip2px(mRoundWidth));
// 文字大小
mProgressTextSize = typedArray.getDimensionPixelSize(R.styleable.ProgressBar_progressTextSize,sp2px(mProgressTextSize));
// 文字颜色
mProgressTextColor = typedArray.getColor(R.styleable.ProgressBar_progressTextColor,mProgressTextColor);
// 释放资源
typedArray.recycle();
// 初始化3个画笔
initPaint();
}
private void initPaint() {
// 内圆弧画笔
mInnerPaint = new Paint();
// 设置抗锯齿
mInnerPaint.setAntiAlias(true);
// 内圆弧颜色
mInnerPaint.setColor(mInnerBackground);
// 圆弧宽度
mInnerPaint.setStrokeWidth(mRoundWidth);
// 只绘制图形边缘(描边) Paint.Style.FILL 只绘制图形内容 Paint.Style.FILL_AND_STROKE 既绘制轮廓也绘制内容
mInnerPaint.setStyle(Paint.Style.STROKE);
//外圆弧画笔
mOuterPaint = new Paint() ;
mOuterPaint.setAntiAlias(true);
mOuterPaint.setColor(mOuterBackground);
mOuterPaint.setStrokeWidth(mRoundWidth); //设置圆弧宽度
mOuterPaint.setStyle(Paint.Style.STROKE);
//文字画笔
mTextPaint = new Paint() ;
mTextPaint.setAntiAlias(true);
mTextPaint.setTextSize(mProgressTextSize);
mTextPaint.setColor(mProgressTextColor);
}
/**
* 测量控件大小
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// 与qq计步器一样,只写最简单的形式,直接获取宽高,也就是说对应到xml布局文件中的宽高属性只能设置固定值,
// 不能是wrap_content,如果想要设置wrap_content,这里首先要获取宽高模式,然后根据宽高模式再去获取宽高
int width = MeasureSpec.getSize(widthMeasureSpec) ;
int height = MeasureSpec.getSize(heightMeasureSpec) ;
// 测量大小 这里保证是正方形:下边2种方式
// setMeasuredDimension(width>height?height:width,width>height?height:width);
setMeasuredDimension(Math.min(width, height), Math.min(width, height));
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// 1. 画内圆[是圆形,不是圆弧]
drawCircle(canvas) ;
// 2. 画外圆弧
drawArc(canvas) ;
// 3. 画文字
drawText(canvas) ;
}
/**
* 画文字
*/
private void drawText(Canvas canvas) {
// 要画的文字
String text = (int)(persent*100)+"%";
Rect rect = new Rect();
// 文字区域
mTextPaint.getTextBounds(text,0,text.length(),rect);
int dx = getWidth()/2 - rect.width()/2;
Paint.FontMetricsInt fontMetricsInt = mTextPaint.getFontMetricsInt();
int dy = (fontMetricsInt.bottom-fontMetricsInt.top)/2-fontMetricsInt.bottom;
// 基线
int baseLine = getHeight()/2+dy;
canvas.drawText(text,dx,baseLine,mTextPaint);
}
/**
* 设置最大进度
*/
public synchronized void setMax(int max){
this.mMax=max;
}
/**
* 当前进度
*/
public synchronized void setProgress(int progress){
if (progress < 0){
}
this.mProgress=progress;
// 不断的获取到当前进度,然后需要不断的刷新
invalidate();
}
/**
* 2. 画外圆弧, 固定写法
*/
private void drawArc(Canvas canvas) {
RectF rectF = new RectF(0+mRoundWidth/2,0+mRoundWidth/2,getWidth()-mRoundWidth/2,getHeight()-mRoundWidth/2);
if (mProgress == 0)
return;
persent = (float)mProgress/mMax;
// param1: 圆弧形状和大小范围 param2: 开始的角度 param3: 扫过的角度 params4: 设置在画圆弧的时候,是否经过圆形 param5: 画笔
canvas.drawArc(rectF,0,persent*360,false,mOuterPaint);
}
/**
* 1. 画内圆:是圆形,不是圆弧, 固定写法
*/
private void drawCircle(Canvas canvas) {
// 中心点
int center = getWidth()/2;
// param1:圆心x坐标 param2:圆心y坐标 param3:圆的半径 param4: 画笔
canvas.drawCircle(center,center,center-mRoundWidth/2,mInnerPaint);
}
private int sp2px(float sp) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp, getResources().getDisplayMetrics());
}
private float dip2px(int dip) {
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dip, getResources().getDisplayMetrics());
}
}
3>:activity_progressbar
4>:ProgressBarActivity
public class ProgressBarActivity extends AppCompatActivity {
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_progressbar);
final ProgressBar mProgressBar = (ProgressBar) findViewById(R.id.progress_bar);
// 设置最大进度
mProgressBar.setMax(4000);
// 属性动画
ValueAnimator valueAnimator = ObjectAnimator.ofFloat(0,4000);
valueAnimator.setDuration(2000);
valueAnimator.start();
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
// 不断的获取当前进度
float currrentProgress = (float) animation.getAnimatedValue();
// 设置当前进度
mProgressBar.setProgress((int) currrentProgress);
}
});
}
}