自定义动画,控制波纹方向:
public class WaveLoadingDrawable extends Drawable implements Animatable {
private static final float WAVE_AMPLITUDE_FACTOR = 0.15f;
private static final float WAVE_SPEED_FACTOR = 0.02f;
private Drawable mDrawable;
private int mWidth, mHeight;
private int mWaveAmplitude, mWaveLength, mWaveOffset, mWaveStep, mWaveLevel;
private ValueAnimator mAnimator;
private float mProgress = 0.3f;
private Paint mPaint;
private Bitmap mMask;
private Matrix mMatrix = new Matrix();
private boolean mRunning = false;
private boolean mIndeterminate = false;
private PorterDuffXfermode sXfermode = new PorterDuffXfermode(PorterDuff.Mode.DST_IN);
private static ColorFilter sGrayFilter = new ColorMatrixColorFilter(new float[]{//变灰
0.264F, 0.472F, 0.088F, 0, 0,
0.264F, 0.472F, 0.088F, 0, 0,
0.264F, 0.472F, 0.088F, 0, 0,
0, 0, 0, 0.5F, 0
});
private int direction;//0:上涨;1:左涨;2:右涨
// private static ColorFilter sGrayFilter = new ColorMatrixColorFilter(new float[]{//变白
// 1.5F, 1.5F, 1.5F, 0, -1,
// 1.5F, 1.5F, 1.5F, 0, -1,
// 1.5F, 1.5F, 1.5F, 0, -1,
// 0, 0, 0, 1, 0
//
// });
private ColorFilter mCurFilter = null;
private Choreographer.FrameCallback mFrameCallback = new Choreographer.FrameCallback() {
@Override
public void doFrame(long l) {
invalidateSelf();
if (mRunning) {
Choreographer.getInstance().postFrameCallback(this);
}
}
};
public WaveLoadingDrawable(Drawable drawable,int direction) {
init(drawable,direction);
}
public WaveLoadingDrawable(Context context, int imgRes,int direction) {
Drawable drawable;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
drawable = context.getDrawable(imgRes);
} else {
drawable = context.getResources().getDrawable(imgRes);
}
init(drawable,direction);
}
private void init(Drawable drawable,int direction) {
this.direction = direction;
mDrawable = drawable;
mWidth = mDrawable.getIntrinsicWidth();
mHeight = mDrawable.getIntrinsicHeight();
if(direction == 0) {
mWaveAmplitude = Math.max(8, (int) (mHeight * WAVE_AMPLITUDE_FACTOR));
mWaveLength = mWidth;
mWaveStep = Math.max(1, (int) (mWidth * WAVE_SPEED_FACTOR));
mMatrix.reset();
mMask = createHorizontalMask(mWidth, mWaveLength, mWaveAmplitude);
}else{
mWaveAmplitude = Math.max(8, (int) (mWidth * WAVE_AMPLITUDE_FACTOR));
mWaveLength = mHeight;
mWaveStep = Math.max(1, (int) (mHeight* WAVE_SPEED_FACTOR));
mMatrix.reset();
mMask = createVerticalMask(mHeight, mWaveLength, mWaveAmplitude);
if(direction == 1){
sXfermode = new PorterDuffXfermode(PorterDuff.Mode.DST_OUT);
}
}
mPaint = new Paint();
mPaint.setFilterBitmap(false);
mPaint.setColor(Color.BLACK);
mPaint.setXfermode(sXfermode);
mAnimator = ValueAnimator.ofFloat(0, 1);
mAnimator.setInterpolator(new DecelerateInterpolator());
mAnimator.setRepeatMode(ValueAnimator.RESTART);
mAnimator.setRepeatCount(ValueAnimator.INFINITE);
mAnimator.setDuration(5000);
mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
setProgress((float) valueAnimator.getAnimatedValue());
if (!mRunning) {
invalidateSelf();
}
}
});
setProgress(0);
start();
}
/**
* Set wave move distance (in pixels) in very animation frame
* @param step distance in pixels
*/
public void setWaveSpeed(int step) {
if(direction ==0) {
mWaveStep = Math.min(step, mWidth / 2);
}else{
mWaveStep = Math.min(step, mHeight / 2);
}
}
/**
* Set wave amplitude (in pixels)
* @param amplitude
*/
public void setWaveAmplitude(int amplitude) {
if(direction ==0) {
amplitude = Math.max(0, Math.min(amplitude, mHeight / 2));
if (mWaveAmplitude != amplitude) {
mWaveAmplitude = amplitude;
mMask = createHorizontalMask(mWidth, mWaveLength, mWaveAmplitude);
invalidateSelf();
}
}else{
amplitude = Math.max(0, Math.min(amplitude, mWidth / 2));
if (mWaveAmplitude != amplitude) {
mWaveAmplitude = amplitude;
mMask = createVerticalMask(mHeight, mWaveLength, mWaveAmplitude);
invalidateSelf();
}
}
}
/**
* Set wave length (in pixels)
* @param length
*/
public void setWaveLength(int length) {
if(direction ==0) {
length = Math.max(8, Math.min(mWidth * 2, length));
if (length != mWaveLength) {
mWaveLength = length;
mMask = createHorizontalMask(mWidth, mWaveLength, mWaveAmplitude);
invalidateSelf();
}
}else{
length = Math.max(8, Math.min(mHeight * 2, length));
if (length != mWaveLength) {
mWaveLength = length;
mMask = createVerticalMask(mHeight, mWaveLength, mWaveAmplitude);
invalidateSelf();
}
}
}
@Override
public void setBounds(int left, int top, int right, int bottom) {
super.setBounds(left, top, right, bottom);
mDrawable.setBounds(left, top, right, bottom);
}
@Override
public int getIntrinsicHeight() {
return mHeight;
}
@Override
public int getIntrinsicWidth() {
return mWidth;
}
@Override
public void draw(Canvas canvas) {
mDrawable.setColorFilter(sGrayFilter);
mDrawable.draw(canvas);
mDrawable.setColorFilter(mCurFilter);
if (mProgress <= 0.001f) {
return;
}
int sc = canvas.saveLayer(0, 0, mWidth, mHeight, null,Canvas.ALL_SAVE_FLAG);
mDrawable.draw(canvas);
if (mProgress >= 0.999f) {
return;
}
mWaveOffset += mWaveStep;
if (mWaveOffset > mWaveLength) {
mWaveOffset -= mWaveLength;
}
switch(direction){
case 0:
if (mWaveLevel > 0) {
mPaint.setColor(Color.TRANSPARENT);
canvas.drawRect(0, 0, mWidth, mWaveLevel, mPaint);
mPaint.setColor(Color.WHITE);
}
mMatrix.setTranslate(-mWaveOffset, mWaveLevel);
canvas.drawBitmap(mMask, mMatrix, mPaint);
break;
case 1:
if (mWaveLevel > 0) {
mPaint.setColor(Color.TRANSPARENT);
canvas.drawRect(mWaveLevel,0,mWidth,mHeight,mPaint);
mPaint.setColor(Color.WHITE);
}
mMatrix.setTranslate(mWaveLevel-2*mWaveAmplitude,-mWaveOffset);
canvas.drawBitmap(mMask, mMatrix, mPaint);
mPaint.setColor(Color.WHITE);
canvas.drawRect(mWaveLevel,0,mWidth,mHeight,mPaint);
break;
case 2:
if (mWaveLevel > 0) {
mPaint.setColor(Color.TRANSPARENT);
canvas.drawRect(0,0,mWaveLevel,mHeight,mPaint);
mPaint.setColor(Color.WHITE);
}
mMatrix.setTranslate(mWaveLevel,-mWaveOffset);
canvas.drawBitmap(mMask, mMatrix, mPaint);
break;
default:
break;
}
canvas.restoreToCount(sc);
}
@Override
protected boolean onLevelChange(int level) {
setProgress(level/100f);
return true;
}
@Override
public void setAlpha(int i) {
mDrawable.setAlpha(i);
}
@Override
public void setColorFilter(ColorFilter colorFilter) {
mCurFilter = colorFilter;
invalidateSelf();
}
@Override
public int getOpacity() {
return PixelFormat.TRANSLUCENT;
}
@Override
public void start() {
mRunning = true;
Choreographer.getInstance().postFrameCallback(mFrameCallback);
}
@Override
public void stop() {
mRunning = false;
Choreographer.getInstance().removeFrameCallback(mFrameCallback);
}
@Override
public boolean isRunning() {
return mRunning;
}
/**
* 开启自动播放
* @param indeterminate
*/
public void setIndeterminate(boolean indeterminate) {
mIndeterminate = indeterminate;
if (mIndeterminate) {
mAnimator.start();
} else {
mAnimator.cancel();
}
}
private void setProgress(float progress) {
mProgress = progress;
if(direction ==0) {
mWaveLevel = mHeight - (int) ((mHeight + mWaveAmplitude * 2) * mProgress);
}else if (direction == 1){
mWaveLevel = (int)((mWidth + mWaveAmplitude * 2) * mProgress);
}else if (direction == 2){
mWaveLevel = mWidth - (int) ((mWidth + mWaveAmplitude * 2) * mProgress);
}
invalidateSelf();
}
/**
* 创建水平方向的波浪
* @param width
* @param length
* @param amplitude
* @return
*/
private static Bitmap createHorizontalMask(int width, int length, int amplitude) {
final int count = (int) Math.ceil((width + length) / (float)length);
Bitmap bm = Bitmap.createBitmap(length * count, amplitude * 2, Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(bm);
Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);
Path path = new Path();
path.moveTo(amplitude,0);
final float stepX = length / 4f;
float x = 0;
float y = 0;
for (int i = 0; i < count * 2; i++) {
x += stepX;
path.quadTo(x, y, x+stepX, amplitude);
x += stepX;
y = bm.getHeight() - y;
}
path.lineTo(bm.getWidth(), bm.getHeight());
path.lineTo(0, bm.getHeight());
path.close();
c.drawPath(path, p);
return bm;
}
/**
* 创建垂直方向的波浪
* @param height
* @param length
* @param amplitude
* @return
*/
private static Bitmap createVerticalMask(int height, int length, int amplitude) {
final int count = (int) Math.ceil((height + length) / (float)length);
Bitmap bm = Bitmap.createBitmap(amplitude * 2,length * count, Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(bm);
Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);
Path path = new Path();
path.moveTo(amplitude, 0);
final float stepX = length / 4f;
float x = 0;
float y = 0;
for (int i = 0; i < count * 2; i++) {
y += stepX;
path.quadTo(x, y, amplitude, y+stepX);
y += stepX;
x = bm.getWidth() - x;
}
path.lineTo(bm.getWidth(), bm.getHeight());
path.lineTo(bm.getWidth(), 0);
path.close();
c.drawPath(path, p);
return bm;
}
}
调用方式:
WaveLoadingDrawable loadingDrawable = new WaveLoadingDrawable(mActivity, R.mipmap.ic_upgrade_red,0);
loadingDrawable.setWaveAmplitude(1);
upgradeImageView.setImageDrawable(upgradeDrawable);
下载进度(1-100):loadingDrawable.setLevel(“当前进度”);