渐进填充图片的自定义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万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章