先说废话
这几天要做一个跟ios一样的菊花进度条,刚开始让UI切了一张图片,然后看看怎么转起来,发现android动画里没有这样的动画,毕竟菊花的每根线是只改变透明度,不改变位置的。最后想到了自定义控件。然后UI又改了样式,这个控件用不到了,写这里保存。
这个菊花口有点大啊,没办法,ui给的要求就是这样。有没有bug我不知道,因为没有经过线上的考验,但是至少思路是这么回事。
public class LoadingProgressBar extends ProgressBar {
private static final String TAG = "LoadingProgressBar" ;
public LoadingProgressBar (Context context) {
super (context);
}
public LoadingProgressBar (Context context, AttributeSet attrs) {
super (context, attrs);
loadAttrs(context, attrs);
initPaint();
}
public LoadingProgressBar (Context context, AttributeSet attrs, int defStyleAttr) {
super (context, attrs, defStyleAttr);
}
private int mWidth;
private int mHeight;
private int paintBold;
private int lineLength;
private int bgPaintColor;
private int textColor;
private int lines;
private Paint bgPaint;
private Paint bfPaint;
private Paint textPaint;
private int progress;
private int max;
private int circle;
private Handler handler = new Handler();
/**
* 加载我们在attrs.xml文件的自定义的属性
*/
private void loadAttrs (Context context, AttributeSet attrs) {
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.loading_progress);
paintBold = array.getDimensionPixelSize(R.styleable.loading_progress_paintBold, 10 );
lineLength = array.getDimensionPixelSize(R.styleable.loading_progress_lineLength, 25 );
bgPaintColor = array.getColor(R.styleable.loading_progress_backgroundColor, Color.GRAY);
lines = array.getInt(R.styleable.loading_progress_lines, 12 );
max = array.getInt(R.styleable.loading_progress_max, 100 );
progress = array.getInt(R.styleable.loading_progress_progress, 0 );
array.recycle();
}
/**
* 初始化画笔
*/
private void initPaint () {
bgPaint = new Paint();
bgPaint.setColor(bgPaintColor);
bgPaint.setAntiAlias(true );
bgPaint.setStrokeWidth(paintBold);
bgPaint.setStrokeJoin(Paint.Join.ROUND);
bgPaint.setStrokeCap(Paint.Cap.ROUND);
circle = 0 ;
}
@Override
protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec) {
super .onMeasure(widthMeasureSpec, heightMeasureSpec);
mWidth = getViewSize(100 , widthMeasureSpec);
mHeight = getViewSize(100 , heightMeasureSpec);
}
/**
* 测量模式 表示意思
* UNSPECIFIED 父容器没有对当前View有任何限制,当前View可以任意取尺寸
* EXACTLY 当前的尺寸就是当前View应该取的尺寸
* AT_MOST 当前尺寸是当前View能取的最大尺寸
*
* @param defaultSize 默认大小
* @param measureSpec 包含测量模式和宽高信息
* @return 返回View的宽高大小
*/
private int getViewSize (int defaultSize, int measureSpec) {
int viewSize = defaultSize;
int mode = MeasureSpec.getMode(measureSpec);
int size = MeasureSpec.getSize(measureSpec);
switch (mode) {
case MeasureSpec.UNSPECIFIED:
viewSize = defaultSize;
break ;
case MeasureSpec.AT_MOST:
viewSize = size;
break ;
case MeasureSpec.EXACTLY:
viewSize = size;
break ;
}
return viewSize;
}
@Override
protected void onDraw (Canvas canvas) {
int x = mWidth / 2 ;
int y = mHeight / 2 ;
int r = x - 5 ;
int alpha = 255 ;
for (int i = 0 ; i < lines; i++) {
switch (circle) {
case 0 :
if (i == 2 || i == 1 || i == 0 ) {
alpha = 255 ;
} else {
alpha = (int ) (255 * (1 - 0.1 * (i + circle - 2 )));
}
break ;
case 1 :
if (i == 1 || i == 0 || i == 11 ) {
alpha = 255 ;
} else {
alpha = (int ) (255 * (1 - 0.1 * (i + circle - 2 )));
}
break ;
case 2 :
if (i == 0 || i == 11 || i == 10 ) {
alpha = 255 ;
} else {
alpha = (int ) (255 * (1 - 0.1 * (i + circle - 2 )));
}
break ;
default :
if (i == 12 - circle + 0 || i == 12 - circle + 1 || i == 12 - circle + 2 ) {
alpha = 255 ;
} else {
alpha = (int ) (255 * (1 - 0.1 * (i + circle - 2 )));
}
break ;
}
Log.e(TAG, "circle = " + circle + " i= " + i + " , alpha= " + alpha);
bgPaint.setAlpha(alpha);
canvas.drawLine(x, y - r, x, y - r + lineLength, bgPaint);
canvas.rotate(-360 / lines, x, y);
}
circle++;
if (circle == 12 ) {
circle = 0 ;
}
handler.postDelayed(runnable, 50 );
}
private Runnable runnable = new Runnable() {
@Override
public void run () {
invalidate();
}
};
@Override
protected void onDetachedFromWindow () {
handler.removeCallbacks(runnable);
super .onDetachedFromWindow();
}
/**
* 为进度设置动画
* ValueAnimator是整个属性动画机制当中最核心的一个类,属性动画的运行机制是通过不断地对值进行操作来实现的,
* 而初始值和结束值之间的动画过渡就是由ValueAnimator这个类来负责计算的。
* 它的内部使用一种时间循环的机制来计算值与值之间的动画过渡,
* 我们只需要将初始值和结束值提供给ValueAnimator,并且告诉它动画所需运行的时长,
* 那么ValueAnimator就会自动帮我们完成从初始值平滑地过渡到结束值这样的效果。
*
* @param start 开始值
* @param current 结束值
* @param duration 动画时长
*/
public void startAnimation (int start, int current, int duration) {
ValueAnimator progressAnimator = ValueAnimator.ofInt(start, current);
progressAnimator.setDuration(duration);
progressAnimator.setTarget(progress);
progressAnimator.setInterpolator(new BounceInterpolator());
progressAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate (ValueAnimator animation) {
progress = (int ) animation.getAnimatedValue();
invalidate();
}
});
progressAnimator.start();
}
}
<com.hyphenate.easeui.widget.LoadingProgressBar
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_centerInParent="true"
loading_progress_:backgroundColor="#9f9c9c"
loading_progress_:lineLength="10dp"
loading_progress_:lines="12"
loading_progress_:max="100"
loading_progress_:paintBold="3dp"
loading_progress_:progress="70" />