效果图:
素材图:(两张图为宽、高一致的png图片)
(图1)
(图2)
原理:
(1)canvas.drawBitmap() 绘制(图1)作为背景。
(2)canvas.clipRect() 从左到右裁剪(图2)要显示出来的区域,方法内参数和ValueAnimatior动画的addUpdateListener()更新监听结合起来实现渐进循环。
(3)canvas.drawBitmap() 使用红色Paint绘制(图2)
上代码
继承自View并实现基本的构造方法
public LoadingView(Context context) {
super(context);
init(context);
}
public LoadingView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public LoadingView(Context context, AttributeSet attrs,
int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
init()方法里边主要获取图1、图2的Bitmap格式、获取图片的宽高、初始化画笔、设置ValueAnimator的动画监听
private void init(Context context) {
bitmapGu = BitmapFactory.decodeResource(context.getResources(), R.mipmap.load_gu);
//获取的必须是全透明的图片,不然红色显示不出来
bitmapTransparent = BitmapFactory.decodeResource(context.getResources(), R.mipmap.load_arrow)
.extractAlpha();
//获取图片的原始宽度、高度作为该View的宽、高
defaultWidth = bitmapGu.getWidth();
defaultHeight = bitmapGu.getHeight();
//设置箭头的填充画笔
paintRed = new Paint();
paintRed.setColor(Color.parseColor("#E94B4B"));
//添加动画监听
animator = ValueAnimator.ofInt(0, bitmapTransparent.getWidth());
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
xCurrent = (int) animation.getAnimatedValue();
postInvalidate();
}
});
animator.setRepeatMode(ValueAnimator.RESTART);
animator.setRepeatCount(ValueAnimator.INFINITE);
//动画填充的动效(插值器)
animator.setInterpolator(new AccelerateDecelerateInterpolator());
animator.setDuration(1200);//填充一遍所用的时间
}
在onMeasure() 方法里将获取到的图片的默认的宽、高设置为View(我在这里默认xml文件里width、height为wrap_content,所以没有对设置match_parent和具体值时候进行判断并设置,有需要的话可以自行作判断。)
如果要增加对设置该控件具体宽、高的判断,需要从两点判断:
(1)xml设置的宽、高比例是否和图片的宽、高比例一致进行显示位置的计算处理
(2)设置的宽、高值和图片真实宽、高倍数计算,在canvas.drawBitmap()时候进行Matrix缩放参数的设置。对于onMeasure()疑问可以参看
http://blog.csdn.net/harvic880925/article/details/47029169
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = getViewSize(defaultWidth, widthMeasureSpec);
int height = getViewSize(defaultHeight, heightMeasureSpec);
setMeasuredDimension(width, height);
}
private int getViewSize(int defaultSize, int measureSpec) {
int mySize;
int mode = MeasureSpec.getMode(measureSpec);
int size = MeasureSpec.getSize(measureSpec);
mySize = (mode == MeasureSpec.EXACTLY) ? size : defaultSize;
return mySize;
}
接下来就是绘制的重点,其实很简单,三行代码。
@Override
protected void onDraw(Canvas canvas) {
drawProgress(canvas);
super.onDraw(canvas);
}
//绘制红色进度方法
private void drawProgress(Canvas canvas) {
canvas.drawBitmap(bitmapGu, 0, 0, null);
canvas.clipRect(0, 0, xCurrent, bitmapTransparent.getHeight());
canvas.drawBitmap(bitmapTransparent, 0, 0, paintRed);
}
加载样式绘制出来了,接下来就是让它如何动起来,在init()方法里设置了ValueAnimator的监听,只要调用animator.start()方法就好了, 那在什么时候调用呢?
这里有两个地方可以调用
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
animator.start();
}
@Override
public void setVisibility(int visibility) {
super.setVisibility(visibility);
if(visibility == View.VISIBLE) {
if(animator.isRunning())
return;
animator.start();
} else {
animator.end();
}
}
加载完成后要让该View消失则调用setVisibility()并结束掉动画。
如果有任何问题,欢迎评论留言。
原文:http://blog.csdn.net/nsacer/article/details/54864094