效果圖:
素材圖:(兩張圖爲寬、高一致的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()並結束掉動畫。
全部代碼
public class LoadingView extends View {
private static final String COLOR_ARROW = "#E94B4B";
private Bitmap bitmapGu;
private Bitmap bitmapTransparent;
private Paint paintRed;
private int defaultWidth;
private int defaultHeight;
private int xCurrent = 0;
private ValueAnimator animator;
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);
}
private void init(Context context) {
bitmapGu = BitmapFactory.decodeResource(context.getResources(), R.mipmap.load_gu);
//獲取的必須是全透明的圖片,不然紅色顯示不出來
bitmapTransparent = BitmapFactory.decodeResource(context.getResources(), R.mipmap.load_arrow)
.extractAlpha();
defaultWidth = bitmapGu.getWidth();
defaultHeight = bitmapGu.getHeight();
paintRed = new Paint();
paintRed.setColor(Color.parseColor(COLOR_ARROW));
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);
}
@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 onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
animator.start();
}
@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);
}
@Override
public void setVisibility(int visibility) {
super.setVisibility(visibility);
if(visibility == View.VISIBLE) {
if(animator.isRunning())
return;
animator.start();
} else {
animator.end();
}
}
}
如果有任何問題,歡迎評論留言。