先来看看效果:
分析下难点:
1. 动画的实现;
2. 边界的控制;
3. 状态保存与恢复;
4. 两种状态的实现,loading状态(不停旋转)、progress状态。
分别来看下。
1. 动画如何实现:
将动画进行拆解,可以发现它其实是一个弧不断变长变短的一个过程+弧本身在绕圆形转动两部分组成。
所以可以分开来处理,弧度变长变短可以通过canvas.drawArc的参数startAngle/SweeepAngle控制,只要改变这两个值即可实现效果。怎么改变?有几种方案,1是通过hander+thread;2是通过View.post();3是通过PropertyAnimation.
弧本身绕圆心运动可以通过Canvas.rotate实现。
private static final float delta = 6f;
private float temp = 0;
class AnimRunnable implements Runnable{
@Override
public void run() {
if (mStartAngle == temp) {
mSweepAngle += delta;
}
if (mSweepAngle >= 280 || mStartAngle > temp) {
mStartAngle += delta;
if(mSweepAngle > 20) {
mSweepAngle -= delta;
}
}
if (mStartAngle > temp + 280) {
temp = mStartAngle;
mStartAngle = temp;
mSweepAngle = 20;
}
postInvalidate();
postDelayed(this,mSpinSpeed);
}
}
2.边界的控制:
需要在onMeasure中控制。在onSizeChanged方法中可以拿到最终的width、height,通过width/height就可以控制progressbar的边界了。
需要注意的是,边界需要是正方形的,所以得考虑宽高不相等的情况以及四个方向padding的大小。
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//计算自己需要的宽度和高度
int width = mCircleRadius*2;
int height = mCircleRadius*2;
//考虑父容器的测量规则
setMeasuredDimension(getResolvedSize(width, widthMeasureSpec), getResolvedSize(height, heightMeasureSpec));
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
int paddingLeft = getPaddingLeft();
int paddingTop = getPaddingTop();
int paddingRight = getPaddingRight();
int paddingBottom = getPaddingBottom();
//简化处理,以最大的padding作为padding
int padding = Math.max(Math.max(paddingLeft, paddingRight), Math.max(paddingTop, paddingBottom));
int diameter;
//保证bounds是一个正方形
if(w >= h){
diameter = h;
mBounds = new RectF(padding+mBarWidth+(w-h)/2,padding+mBarWidth,diameter-padding-mBarWidth+(w-h)/2,diameter-padding-mBarWidth);
}else if(w < h){
diameter = w;
mBounds = new RectF(padding+mBarWidth,padding+mBarWidth+(h-w)/2,diameter-padding-mBarWidth,diameter-padding-mBarWidth+(h-w)/2);
}
}
3.状态的保存与恢复:
progressbar的状态不能因为横竖屏切换等问题丢失,所以需要通过重写onSaveInstanceState/onRestoreInstanceState来保存/恢复状态.
@Override
protected void onRestoreInstanceState(Parcelable state) {
if(! (state instanceof SavedState)){
super.onRestoreInstanceState(state);
return;
}
//先恢复父类的状态
SavedState savedState = (SavedState) state;
super.onRestoreInstanceState(savedState.getSuperState());
//在恢复自己的状态
this.mCurMode = savedState.mCurMode == 0 ? Mode.INDETERMINATE : Mode.DETERMINATE;
this.mRimWidth = savedState.mRimWidth;
this.mRimColor = savedState.mRimColor;
this.mBarColor = savedState.mBarColor;
this.mBarWidth = savedState.mBarWidth;
this.showRim = savedState.showRim;
this.isAnimStart = savedState.isAnimStart;
this.mProgress = savedState.mProgress;
}
@Override
protected Parcelable onSaveInstanceState() {
//相当于是做了一层包装
//先保存父类的状态,然后包装,再保存自己的状态
Parcelable parcelable = super.onSaveInstanceState();
SavedState savedState = new SavedState(parcelable);
savedState.mCurMode = (this.mCurMode == Mode.INDETERMINATE) ? 0 : 1;
savedState.mRimWidth = this.mRimWidth;
savedState.mRimColor = this.mRimColor;
savedState.mBarColor = this.mBarColor;
savedState.mBarWidth = this.mBarWidth;
savedState.showRim = this.showRim;
savedState.isAnimStart = this.isAnimStart;
savedState.mProgress = this.mProgress;
return savedState;
}
4.两种状态的实现:
自然是通过一个变量记录当前模式,在onDraw中通过判断模式进行不同的绘制操作。
版权声明:本文为博主原创文章,未经博主允许不得转载。
原文地址:http://blog.csdn.net/chdjj/article/details/47379409