自定义圆形进度条的实现

概述

Android中自带有进度条,但是有的时候自带的进度条不能满足我们的需求,这时候就需要自定义进度条了,今天带来的就是一个自定义的圆形进度条首先来看效果,效果如下所示。

自定义圆形进度条

实现

从上面的效果可以看出,主要有以下几个自定义属性:

  • 背景颜色
  • 进度扇形颜色
  • 半径
  • 起始角度

因此,在attrs.xml中定义如下属性:

1
2
3
4
5
6
7
8
9
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="SimpleRoundProgressBar">
<attr format="color" name="roundColor"/>
<attr format="color" name="roundProgressColor"/>
<attr format="dimension" name="circleRadius"/>
<attr format="integer" name="startAngle"/>
</declare-styleable>
</resources>

下面是SimpleRoundProgressBar代码,在onMeasure当中确定view的大小,在onDraw来进行绘制。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
package com.easyliu.demo.customizeview;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;

/**
* Created by easyliu on 2017/2/24.
*/

public class SimpleRoundProgressBar extends View {
private Paint mPaint;//画笔
private RectF mRectF;//扇形绘制的矩形范围
private int mRoundColor;//圆环的颜色
private int mRoundProgressColor; //进度条的颜色
private float mRadius;//半径
private int mWidth; //宽度
private int mHeight; //高度
private int mCenterX; //中心X坐标
private int mCenterY; //中心Y坐标
private int mStartAngle; //初始角度
private int mSweepAngle; //扫过的角度
private static final int DEFAULT_INIT_ANGLE = 0;//默认的初始化角度
private static final int DEFAULT_RADIUS = 10;//默认的半径

public SimpleRoundProgressBar(Context context) {
this(context, null);
}

public SimpleRoundProgressBar(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}

public SimpleRoundProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mPaint = new Paint();
mRectF = new RectF();
TypedArray typedArray =
context.obtainStyledAttributes(attrs, R.styleable.SimpleRoundProgressBar);
mRoundColor = typedArray.getColor(R.styleable.SimpleRoundProgressBar_roundColor, Color.GRAY);
mRoundProgressColor =
typedArray.getColor(R.styleable.SimpleRoundProgressBar_roundProgressColor, Color.RED);
mRadius =
typedArray.getDimension(R.styleable.SimpleRoundProgressBar_circleRadius, DEFAULT_RADIUS);
mStartAngle =
typedArray.getInteger(R.styleable.SimpleRoundProgressBar_startAngle, DEFAULT_INIT_ANGLE);
typedArray.recycle();
}

@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//获取测量模式
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
//获取测量大小
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);

//如果为确定值
if (heightMode == MeasureSpec.EXACTLY) {
mHeight = heightSize;
} else {
//如果为wrap_content,高度为半径大小乘以2,注意padding
mHeight = (int) (mRadius * 2) + getPaddingTop() + getPaddingBottom();
}

//如果为确定值
if (widthMode == MeasureSpec.EXACTLY) {
mWidth = widthSize;
mHeight=mWidth;//宽和高相等
} else {
//如果为wrap_content,宽度为半径大小乘以2,注意padding
mWidth = (int) (mRadius * 2) + getPaddingLeft() + getPaddingRight();
}

//设置视图的大小
setMeasuredDimension(mWidth, mHeight);
}

@Override protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mPaint.setColor(mRoundColor);
mPaint.setAntiAlias(true);
mCenterX = mWidth / 2;
mCenterY = mHeight / 2;
//注意处理padding
mRadius = (mWidth - getPaddingLeft() - getPaddingRight()) / 2;
//画圆
canvas.drawCircle(mCenterX, mCenterY, mRadius, mPaint);
mPaint.setColor(mRoundProgressColor);
//注意处理padding
mRectF.left = getPaddingLeft();
mRectF.right = mWidth - getPaddingRight();
mRectF.top = getPaddingTop();
mRectF.bottom = mHeight - getPaddingBottom();
//画扇形
canvas.drawArc(mRectF, (float) mStartAngle, mSweepAngle, true, mPaint);
}

public int getRoundColor() {
return mRoundColor;
}

public void setRoundColor(int roundColor) {
this.mRoundColor = roundColor;
}

/**
* 得到初始角度
*/
public synchronized int getStartAngle() {
return mStartAngle;
}

/**
* 设置初始角度
*/
public synchronized void setStartAngle(int startAngle) {
if (startAngle < -360) {
throw new IllegalArgumentException("the angle can not less than -360");
}
if (startAngle > 360) {
throw new IllegalArgumentException("the angle can not larger than 360");
}
this.mStartAngle = startAngle;
}

/**
* 得到扫过的角度
*/
public synchronized int getSweepAngle() {
return mSweepAngle;
}

/**
* 设置扫过的角度,相对于起始点
*
* @param sweepAngle 0~360
*/
public synchronized void setSweepAngle(int sweepAngle) {
if (sweepAngle < 0) {
throw new IllegalArgumentException("the angle can not less than 0");
}
if (sweepAngle > 360) {
throw new IllegalArgumentException("the angle can not larger than 360");
}
this.mSweepAngle = sweepAngle;
postInvalidate();
}
}

定义好了之后就可以使用了,首先是xml文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:easyliu="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.easyliu.demo.customizeview.RoundProgressBarActivity"
>

<com.easyliu.demo.customizeview.SimpleRoundProgressBar
android:id="@+id/progress_demo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:padding="10dp"
easyliu:circleRadius="50dp"
easyliu:roundColor="#5F000000"
easyliu:roundProgressColor="#ff8d33"
/>

<com.easyliu.demo.customizeview.SimpleRoundProgressBar
android:id="@+id/progress_demo2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/progress_demo"
android:layout_centerHorizontal="true"
android:padding="10dp"
easyliu:circleRadius="60dp"
easyliu:roundColor="@color/colorPrimary"
easyliu:roundProgressColor="@color/colorAccent"
/>

</RelativeLayout>

然后是Activity代码,在代码中使用定时器来定时更新进度即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
package com.easyliu.demo.customizeview;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import java.util.Timer;
import java.util.TimerTask;

public class RoundProgressBarActivity extends AppCompatActivity {
private int mCurrentAngle = 0;
private SimpleRoundProgressBar mRoundProgressBar1;
private SimpleRoundProgressBar mRoundProgressBar2;

@Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_progress_bar);
initViews();
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override public void run() {
mCurrentAngle++;
mRoundProgressBar1.setSweepAngle(mCurrentAngle);
mRoundProgressBar2.setSweepAngle(mCurrentAngle);
if (mCurrentAngle >= 360) {
mCurrentAngle = 0;
}
}
}, 0, 20);
}
private void initViews(){
mRoundProgressBar1 =
(SimpleRoundProgressBar) findViewById(R.id.progress_demo);
mRoundProgressBar1.setStartAngle(-90);
mRoundProgressBar2= (SimpleRoundProgressBar) findViewById(R.id.progress_demo2);
mRoundProgressBar2.setStartAngle(0);
}
}

这样就完成了一个简单的圆形进度条的自定义。