关键代码:
private void init(Context context,AttributeSet attrs) {
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.CircleView);
mRadiu = ta.getDimensionPixelSize(R.styleable.CircleView_radiu,0);
mBgColor = ta.getColor(R.styleable.CircleView_bg_color,0);
ta.recycle();
}
下面写一个下载的环形进度条为例,如图:
1、在values文件夹下新建attrs.xml文件,声明要自定义的属性
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="CircleProgressBar">
<attr name="progress_color" format="color"/>
<attr name="background_color" format="color"/>
<attr name="stroke_width" format="dimension"/>
<attr name="max_value" format="integer"/>
<attr name="current_value" format="integer"/>
<attr name="text_size" format="dimension"/>
<attr name="text_color" format="color"/>
</declare-styleable>
</resources>
2、写自定义的view
public class CircleProgressBar extends View {
public static int TOTAL_DURATION = 10000;
public static int DEFAULT_PROGRESS_COLOR = Color.BLUE;
public static int DEFAULT_BACKGROUND_COLOR = Color.GRAY;
public static int DEFAULT_STROKE_WIDTH = ScreenSizeUtil.dpToPx(40);
public static int DEFAULT_TEXT_SIZE = ScreenSizeUtil.spToPx(28);
public static int DEFAULT_TEXT_COLOR = Color.BLACK;
private Paint mBackgroundPaint = new Paint();
private Paint mPaint = new Paint();
private Paint mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private int mProgressColor;
private int mBackgroundColor;
private int mStrokeWidth;
private int mMaxValue = 100;
private int mCurrentValue = 0;
private int mCircleRadius;
private Point mCenterPoint; //环形进度条的原点坐标
private RectF mOval = new RectF();
private ValueAnimator mAnimator;
private boolean isAnimating = false;
private String mProgress = "";
private ProgressChangeListener mListener;
public CircleProgressBar(Context context) {
super(context);
init(context, null);
}
public CircleProgressBar(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
public CircleProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
private void init(Context context, AttributeSet attrs) {
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.CircleProgressBar);
mProgressColor = ta.getColor(R.styleable.CircleProgressBar_progress_color, DEFAULT_PROGRESS_COLOR);
mBackgroundColor = ta.getColor(R.styleable.CircleProgressBar_background_color, DEFAULT_BACKGROUND_COLOR);
mStrokeWidth = ta.getDimensionPixelSize(R.styleable.CircleProgressBar_stroke_width, DEFAULT_STROKE_WIDTH);
mMaxValue = ta.getInt(R.styleable.CircleProgressBar_max_value, 100);
mCurrentValue = ta.getInt(R.styleable.CircleProgressBar_current_value, 0);
int textSize = ta.getDimensionPixelSize(R.styleable.CircleProgressBar_text_size, DEFAULT_TEXT_SIZE);
int textColor = ta.getColor(R.styleable.CircleProgressBar_text_color, DEFAULT_TEXT_COLOR);
ta.recycle();
initPaint(textSize, textColor);
setProgress(mCurrentValue);
mCenterPoint = new Point();
}
//设置进度条当前值
public void setProgress(int progress) {
if (progress > mCurrentValue && progress < 0) {
return;
}
if (isAnimating) {
isAnimating = false;
mAnimator.cancel();
}
int oldValue = mCurrentValue;
mCurrentValue = progress;
startAnimation(oldValue, progress);
}
public void stopProgress(){
if (isAnimating) {
isAnimating = false;
mAnimator.cancel();
}
}
private void initPaint(int textSize, int textColor) {
mTextPaint.setColor(textColor);
mTextPaint.setTextSize(textSize);
mTextPaint.setTextAlign(Paint.Align.CENTER);
mPaint.setColor(mProgressColor);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(mStrokeWidth);
mBackgroundPaint.setColor(mBackgroundColor);
mBackgroundPaint.setStyle(Paint.Style.STROKE);
mBackgroundPaint.setStrokeWidth(mStrokeWidth);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = getMeasuredWidth() - getPaddingLeft() - getPaddingRight();
int height = getMeasuredHeight() - getPaddingTop() - getPaddingBottom();
//Math.min(a, b) 返回a、b中叫较小的一个
mCircleRadius = (Math.min(width, height) - mStrokeWidth) / 2;
mCenterPoint.set(width / 2, height / 2);
}
@Override
protected void onDraw(Canvas canvas) {
if (mListener != null){
mProgress = mListener.changeProgress(this,mCurrentValue,mMaxValue);
}
canvas.drawCircle(mCenterPoint.x, mCenterPoint.y, mCircleRadius, mBackgroundPaint);
mOval.left = mCenterPoint.x - mCircleRadius;
mOval.right = mCenterPoint.y + mCircleRadius;
mOval.top = mCenterPoint.y - mCircleRadius;
mOval.bottom = mCenterPoint.y + mCircleRadius;
/** * 画圆弧 drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter, Paint paint) * 第一个参数:设置圆弧的形状和大小的范围 * 第二个参数:设置圆弧是从哪个角度来顺时针绘画的 * 第三个参数:设置圆弧扫过的角度 * 第四个参数:设置圆弧在绘画的时候是否经过圆形 */
canvas.drawArc(mOval, 270, 360 * mCurrentValue / mMaxValue, false, mPaint);
Paint.FontMetricsInt fontMetrics = mTextPaint.getFontMetricsInt();
float baseline = mOval.top + (mOval.height() - fontMetrics.bottom + fontMetrics.top) / 2 - fontMetrics.top;
canvas.drawText(mProgress, mCenterPoint.x, baseline, mTextPaint);
}
private void startAnimation(int start, int end) {
mAnimator = ValueAnimator.ofInt(start, end);
int duration = Math.abs(TOTAL_DURATION * (end - start) / mMaxValue);
mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mCurrentValue = (int) animation.getAnimatedValue();
invalidate();
}
});
mAnimator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
isAnimating = true;
}
@Override
public void onAnimationEnd(Animator animation) {
isAnimating = false;
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
mAnimator.setDuration(duration);
mAnimator.start();
}
public interface ProgressChangeListener{
String changeProgress(CircleProgressBar bar,int currentValue,int maxValue);
}
public void setOnProgressChangeListener(ProgressChangeListener progressChangeListener){
this.mListener = progressChangeListener;
}
}
3、使用:
public class MainActivity extends AppCompatActivity {
private CircleProgressBar mBar;
private Button mStartBtn, mResumeBtn,mStopBtn;
private int count;
protected static final int STOP = 0x10000;
protected static final int NEXT = 0x10001;
private Handler myHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case STOP:
break;
case NEXT:
if (!Thread.currentThread().isInterrupted()) {
mBar.setProgress(count);
}
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
setClick();
}
private void initView() {
mBar = (CircleProgressBar) findViewById(R.id.bar);
mStartBtn = (Button) findViewById(R.id.btn_start);
mResumeBtn = (Button) findViewById(R.id.btn_resume);
mStopBtn = (Button) findViewById(R.id.btn_stop);
mBar.setOnProgressChangeListener(new CircleProgressBar.ProgressChangeListener() {
@Override
public String changeProgress(CircleProgressBar bar, int currentValue, int maxValue) {
return 100 * currentValue / maxValue + "%";
}
});
}
private void setClick() {
mStartBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
count = 0;
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 20; i++) {
try {
count = (i + 1) * 5;
if (i == 19) {
Message msg = new Message();
msg.what = STOP;
myHandler.sendMessage(msg);
} else {
Message msg = new Message();
msg.what = NEXT;
myHandler.sendMessage(msg);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}).start();
}
});
mResumeBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mBar.setProgress(0);
}
});
mStopBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mBar.stopProgress();
}
});
}
}