package com.etiennelawlor.loop.ui;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ClipDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.Gravity;
import android.widget.ImageView;
import com.etiennelawlor.loop.R;
/**
* Created by chiemy on 15/8/19.
*/
public class LoadingImageView extends ImageView {
// region Member Variables
private Paint imagePaint;
private BitmapShader shader;
private Paint paint;
private int imageHeight, imageWidth;
private int maskColor = Color.TRANSPARENT;
private ClipDrawable clipDrawable;
private Drawable maskDrawable;
private ObjectAnimator animator;
private int gravity = Gravity.LEFT;
private int orientaion = ClipDrawable.HORIZONTAL;
private float scaleX,scaleY;
private boolean autoStart = true;
private long animDuration = 800;
private float[] f = new float[9];
// endregion
// region Constructors
public LoadingImageView(Context context) {
this(context, null);
}
public LoadingImageView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public LoadingImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
initAttrs(context, attrs);
}
// endregion
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
getImageMatrix().getValues(f);
scaleX = f[Matrix.MSCALE_X];
scaleY = f[Matrix.MSCALE_Y];
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//canvas.drawRect(0, maskHeight, getWidth(), getHeight(), paint);
canvas.save();
canvas.scale(scaleX, scaleY);
clipDrawable.setBounds(getDrawable().getBounds());
clipDrawable.draw(canvas);
canvas.restore();
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
stopAnim();
}
@Override
public void setImageDrawable(Drawable drawable) {
super.setImageDrawable(drawable);
if(maskColor != Color.TRANSPARENT){
init();
initMaskBitmap(maskColor);
initAnim();
}
}
// region Helper Methods
private void initAttrs(Context context, AttributeSet attrs){
if(attrs == null){
return;
}
TypedArray t = context.obtainStyledAttributes(attrs, R.styleable.LoadingImageView);
maskColor = t.getColor(R.styleable.LoadingImageView_mask_color, maskColor);
autoStart = t.getBoolean(R.styleable.LoadingImageView_anim_auto_start, autoStart);
setMaskColor(maskColor);
t.recycle();
}
private void init() {
if (paint == null) {
imagePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
imagePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP));
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
}
}
private Bitmap combineImages(Bitmap bgd, Bitmap fg) {
Bitmap bmp = Bitmap.createBitmap(imageWidth, imageHeight, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bmp);
canvas.drawBitmap(bgd, 0, 0, null);
canvas.drawBitmap(fg, 0, 0, imagePaint);
return bmp;
}
private void initMaskBitmap(int maskColor) {
Drawable drawable = getDrawable();
if(drawable == null){
return;
}
Bitmap bgd = ((BitmapDrawable) drawable).getBitmap();
imageWidth = drawable.getIntrinsicWidth();
imageHeight = drawable.getIntrinsicHeight();
Bitmap fg = Bitmap.createBitmap(imageWidth, imageHeight, Bitmap.Config.ARGB_8888);
Canvas fgCanvas = new Canvas(fg);
fgCanvas.drawColor(maskColor);
Bitmap bitmap = combineImages(bgd, fg);
maskDrawable = new BitmapDrawable(bitmap);
clipDrawable = new ClipDrawable(maskDrawable, gravity, orientaion);
//shader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
//paint.setShader(shader);
}
private void setMaskHeight(int y) {
int maskHeight = y;
invalidate();
}
private void initAnim() {
stopAnim();
//animator = ObjectAnimator.ofInt(this, "maskHeight", 0, imageHeight);
animator = ObjectAnimator.ofInt(clipDrawable, "level", 0, 10000);
animator.setDuration(animDuration);
animator.setRepeatCount(ValueAnimator.INFINITE);
animator.setRepeatMode(ValueAnimator.RESTART);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
invalidate();
}
});
if(autoStart){
animator.start();
}
}
private void stopAnim(){
if(animator != null){
animator.cancel();
}
}
/**
* 设置动画时长
*/
public void setMaskAnimDuration(long duration) {
animDuration = duration;
initAnim();
}
/**
* 开始播放动画
*/
public void startMaskAnim() {
if (animator != null) {
animator.start();
}
}
public void setMaskColor(int color) {
initMaskBitmap(color);
initAnim();
}
/**
* 设置方向
* @param orientation {@link MaskOrientation}
*/
public void setMaskOrientation(int orientation){
switch (orientation){
case MaskOrientation.LeftToRight:
gravity = Gravity.LEFT;
orientaion = ClipDrawable.HORIZONTAL;
break;
case MaskOrientation.RightToLeft:
gravity = Gravity.RIGHT;
orientaion = ClipDrawable.HORIZONTAL;
break;
case MaskOrientation.TopToBottom:
gravity = Gravity.TOP;
orientaion = ClipDrawable.VERTICAL;
break;
case MaskOrientation.BottomToTop:
default:
gravity = Gravity.BOTTOM;
orientaion = ClipDrawable.VERTICAL;
break;
}
if(maskDrawable == null){
return;
}
clipDrawable = new ClipDrawable(maskDrawable, gravity, orientaion);
initAnim();
}
public int getMaskOrientation() {
int maskOrientation = MaskOrientation.LeftToRight;
return maskOrientation;
}
// endregion
// region Inner Classes
public static final class MaskOrientation{
public static final int LeftToRight = 1;
public static final int RightToLeft = 2;
public static final int TopToBottom = 3;
public static final int BottomToTop = 4;
}
// endregion
}