先说废话
这几天要做一个跟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" />