漸進填充圖片的自定義loading加載樣式

效果圖:這裏寫圖片描述

素材圖:(兩張圖爲寬、高一致的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();
        }
    }
}

如果有任何問題,歡迎評論留言。


發佈了33 篇原創文章 · 獲贊 10 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章