Android自定义一个简单好看的ProgressDialog

Android中,经常会需要用到ProgressDialog这个控件,但是5.0之前,Google官方提供的ProgressDialog大家好像都不怎么看的上眼,通常我们都会自己用图片+动画的形式实现自己闪亮的ProgressDialog,但是更好的方法是我们自己去画一个ProgressDialog,简单好用就行!

下面就来介绍如何画出这样简单的自己的ProgressDialog,也是我们实现Android自定义View的一个开始。

自定义Android控件,我们可以继承View。但是这里我继承的是ImageView,ImageView是View的子类,同继承View类似,但是ImageView为我们提供了许多额外的功能,想想平时使用ImageView那么多的方法属性。

看效果图,需要两种颜色去实现不同的进度条,我们首先将这两种颜色定义在values/attrs.xml(这个文件是自定义控件时定义自己控件属性的一个资源文件)文件下,代码如下:

1
2
3
4
5
6
<resources>
<declare-styleable name="EUIProgressBar">
<attr name="strokecolor" format="color" />
<attr name="fillcolor" format="color" />
</declare-styleable>
</resources>

在后面引用我们自定义ProgressDialog的时候,我们就可以在XML文件中去定义自己想要的颜色,后面会讲到。

接下来,就开始处理我们自己的ProgressDialog部分的代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class CustomProgressBar extends ImageView {
public CustomProgressBar(Context context){
super(context);
}
public CustomProgressBar(Context context, AttributeSet attrs){
//在XML文件中使用自定义View时,必须添加这个构造方法
super(context, attrs);
init(context, attrs);
}
public CustomProgressBar(Context context, AttributeSet attrs, int defStyleAttr){
super(context, attrs, defStyleAttr);
init(context, attrs);
}
}

这就是我们自己的ProgressDialog,这里我们叫它CustomProgressBar,其中有三个构造方法。

在构造方法中,调用了一个自己写的init()方法,主要完成一些初始化的工作,如下:

1
2
3
4
5
6
7
8
9
private void init(final Context context, final AttributeSet attrs){
final TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.EUIProgressBar);
mStrokeColor = typedArray.getColor(R.styleable.EUIProgressBar_strokecolor, getResources().getColor(R.color.strokecolor));//获取自定义的strokecolor,未定义或者获取失败就为我们默认值
mFillColor = typedArray.getColor(R.styleable.EUIProgressBar_fillcolor, getResources().getColor(R.color.fillcolor));//获取自定义的fillcolor,未定义或者获取失败就为我们默认值
typedArray.recycle();//回收当前的typedArray,后面可能会重新利用
mPaint = new Paint();
mPaint.setAntiAlias(true);
mAccelerateInterpolator = new AccelerateInterpolator();//加速的Interpolator
}

绘制的时候,我们需要知道绘制的圆环的半径,这里我们将半径固定为整个View宽度或者高度的1/2减去一个padding值。在View类中,有一个onSizeChanged(int w, int h, int oldw, int oldh)方法,这里面可以获取当前View最新的宽、高和之前的宽、高,覆写这个方法并在其中初始化我们的圆环的半径以及绘制进度条圆弧所在的矩形。代码如下:

1
2
3
4
5
6
7
8
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mWidth = w;//宽
mHeight = h;//高
mRingRadius = mWidth / 2 - CIRCLE_RADIUS;//圆环半径
mRect = new RectF(0 + CIRCLE_RADIUS, 0 + CIRCLE_RADIUS, mWidth - CIRCLE_RADIUS, mHeight - CIRCLE_RADIUS);//进度条所在的矩形
}

接下来,就是绘制我们的CustomProgressBar了。覆写onDraw(Canvas canvas)方法并实现自己的绘制代码,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (!isDraw || mPaint == null){
return;
}
//绘制圆环
mPaint.setColor(mStrokeColor);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(STROKE_WIDTH);
canvas.drawCircle(mWidth / 2, mHeight / 2, mRingRadius, mPaint);
//绘制圆弧
mPaint.setColor(mFillColor);
mPaint.setStyle(Paint.Style.STROKE);
canvas.drawArc(mRect, 0, mAccelerateInterpolator.getInterpolation(mDegress), false, mPaint);//这里面用了一个加速的Interpolator去改变圆弧当前的值,主要是让我们的绘制过程看上去是一个加速的过程
}

现在就已经绘制了自己圆环以及其中的进度条,当然这还是静止的,我们还要让其动起来。很简单,让一个Timer去执行一个TimerTask,并改变圆弧的弧度,代码:

1
2
3
4
5
6
7
8
9
10
11
12
mTask = new TimerTask() {
@Override
public void run() {
if (mDegress == TSZ_FINAL){//绘制满一圈之后,交换两种颜色重新绘制,看起来就像是有交替的感觉
exchangeColor();
}
mDegress = mDegress == TSZ_FINAL ? 0 : (float)(mDegress + 0.1);//绘制满一圈之后,重置数据
postInvalidate();//调用该方法通知重绘当前View(调用onDraw方法)
}
};
mTimer = new Timer();
mTimer.schedule(mTask, 0, 7);

差不多就完成了,接下来就是使用这个CustomProgressBar,就像平常在布局文件中使用一个普通控件一样去使用这个CustomProgressBar,不过要在布局文件最顶层加上声明:

xmlns:whilu="http://schemas.android.com/apk/res-auto"

最后添加这个控件,其中我们用到了自定义的属性whilu:strokecolor和whilu:fillcolor,如下所示:

1
2
3
4
5
6
<com.github.wihlu.library.CustomProgressBar
android:id="@+id/cusprogressbar"
android:layout_width="80dp"
android:layout_height="80dp"
whilu:strokecolor="#ff666666"
whilu:fillcolor="#ff4387F0" />

最后的效果就是最开始的效果图。

这里简单的示范了自定义一个控件的基本流程,当然还有很多可以扩展的地方。

源码:https://github.com/whilu/EUIProgressBar