Windows风格的Loading动画Android实现(2)

来源:互联网 发布:分色软件 编辑:程序博客网 时间:2024/05/22 17:34

前言

众所周知,为了不ANR,不可以在UI线程上执行耗时的操作。所以为了效率,也为了通用,我把计算绘制参数的操作放到工作线程中去了。参考了这篇文章。

首先创建一个工作线程(workerThread),一个与workerThread关联的Handler(workerHandler),还有一个和UI线程关联的Handler(uiHandler)。在onDraw()执行结束之后,会通过workerHander发消息,workerThread收到消息会去重新计算绘制参数。完成之后,会通过uiHandler发消息,UI线程收到消息之后调用invalidate(),会导致onDraw()被执行。进入下一次循环。

这样就实现了,重新计算绘制参数在workerThread执行,invalidate()在UI线程执行。在这里,handler充当信使的作用,它可以在其他线程向自己关联的线程发消息、post runnable等等。

HandlerThread知识

HandlerThread类的注释:

Handy class for starting a new thread that has a looper. The looper can then be  used to create handler classes. Note that start() must still be called.

Handler类的注释

/*** A Handler allows you to send and process {@link Message} and Runnable* objects associated with a thread's {@link MessageQueue}.  Each Handler* instance is associated with a single thread and that thread's message* queue.  When you create a new Handler, it is bound to the thread /* message queue of the thread that is creating it -- from that point on,* it will deliver messages and runnables to that message queue and execute* them as they come out of the message queue.*  * <p>There are two main uses for a Handler: (1) to schedule messages and* runnables to be executed as some point in the future; and (2) to enqueue* an action to be performed on a different thread than your own.......

源码

public class LoadingView extends View {    /**     * A list that contains the cx of each point.     */    private List<Float> cx;    /**     * The cy of every point is the same.     */    private float cy;    /**     * The radius of every point is the same.     */    private float radius;    /**     * The paints that used to draw each point.     */    private List<Paint> paints;    /**     * The length that point transfer to enter and exit.     */    private float dx;    private List<Float> dxs;    /**     * The offset between each point.     */    private float offset;    /**     * Used in animation.     */    private long startMillis = -1;    /**     * Used to make translation more smooth     */    private Interpolator enterInterpolator, exitInterpolator;    /**     * The time one point enter or exit     */    private long duration;    /**     * The moving velocity of the point which is not entering or exiting     */    private float v = 0.04F;    /**     * The number of points     */    private int pointNum;    private float cxOffest;    private Handler uiHandler;    private HandlerThread workerThread;    private Handler workerHandler;    public LoadingView(Context context) {        super(context);        init();    }    public LoadingView(Context context, AttributeSet attrs) {        super(context, attrs);        init();    }    public LoadingView(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        init();    }    private void init(){        pointNum = 4;        cx = new ArrayList<Float>(Collections.nCopies(pointNum, 0.0F));        Paint paint = new Paint();        paint.setDither(true);        paint.setAntiAlias(true);        paint.setColor(Color.parseColor("#00BCD4"));        paint.setAlpha(0);        paints = new ArrayList<Paint>();        for (int i = 0; i < pointNum; i++) {            paints.add(new Paint(paint));        }        enterInterpolator = new DecelerateInterpolator(1.5F);        exitInterpolator = new AccelerateInterpolator(2.0F);        duration = 600;        uiHandler = new Handler(new Handler.Callback() {            @Override            public boolean handleMessage(Message message) {                invalidate();                return true;            }        });        workerThread = new HandlerThread("workerThread");        workerThread.start();        workerHandler = new Handler(workerThread.getLooper(), new Handler.Callback() {            @Override            public boolean handleMessage(Message message) {                updateDrawParams();                uiHandler.sendEmptyMessage(0);                return true;            }        });    }    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        super.onMeasure(widthMeasureSpec, heightMeasureSpec);        initSize();    }    private void initSize(){        cy = getMeasuredHeight() / 2;        radius = getMeasuredHeight() / 3;        dx = getMeasuredWidth() / 3;        cxOffest = (getMeasuredWidth() - 2*dx - v*duration*3) * 0.5F;        offset = radius * 3;    }    @Override    protected void onDraw(Canvas canvas) {        for (int i = 0; i < cx.size(); i++) {            canvas.drawCircle(cx.get(i), cy, radius, paints.get(i));        }        workerHandler.sendEmptyMessage(0);//update draw params on worker thread    }    @Override    protected void onDetachedFromWindow() {        super.onDetachedFromWindow();        workerThread.quit();    }    private void updateDrawParams(){        long currentMillis = System.currentTimeMillis();        if (startMillis == -1){            startMillis = currentMillis;        }        // (pointNum * 2 * duration) is a cycle        long passMills = (currentMillis - startMillis) % (pointNum * 2 * duration);        // updateDrawParams each point's cx and alpha        for (int i = 0; i < cx.size(); i++) {            long step = passMills / duration;            float animationFraction = (passMills % duration) * 1.0F / duration;            float enterX, transX, exitX;            if (step < 4) { // entering half                if (i < step) {                    enterX = dx - i*offset + i*duration*v;                    transX = (passMills - (i + 1) * duration) * v;                    exitX = 0;                    paints.get(i).setAlpha(255);                } else if (i == step) {                    float interpolatedFraction = enterInterpolator.getInterpolation(animationFraction);                    enterX = interpolatedFraction*dx - i*offset + i*duration*v;                    transX = 0;                    exitX = 0;                    paints.get(i).setAlpha((int) (255*interpolatedFraction));                } else {                    enterX = 0;                    transX = 0;                    exitX =0;                    paints.get(i).setAlpha(0);                }            } else { // exiting half                if (i < step-4){                    enterX = dx - i*offset + i*duration*v;                    transX = (passMills - (i + 1) * duration) * v;                    exitX = dx;                    paints.get(i).setAlpha(0);                } else if (i == step-4){                    float interpolatedFraction = exitInterpolator.getInterpolation(animationFraction);                    enterX = dx - i*offset + i*duration*v;                    transX = (passMills - (i + 1) * duration) * v;                    exitX = interpolatedFraction * dx;                    paints.get(i).setAlpha((int) (255*(1-interpolatedFraction)));                } else {                    enterX = dx - i*offset + i*duration*v;                    transX = (passMills - (i + 1) * duration) * v;                    exitX = 0;                    paints.get(i).setAlpha(255);                }            }            cx.set(i, cxOffest + enterX + transX + exitX);        }    }}
0 0
原创粉丝点击