您的位置:首页 > 移动开发 > Android开发

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

2015-07-13 10:00 405 查看

效果



前言

  还不够完善,只做学习之用。

原理

  不停的重绘,即不停的改变点的位置以及透明度,不停的invaldate。所以,关键就在于根据动画执行时间确定点的位置以及透明度。

  首先定义,一个点飞入飞出所用时间为duration,点的数量为pointNum,那么可知pointNum*duration*2为一个周期。我们把动画执行时间对周期取余,自然就可得到循环重复效果。

  在一个周期里面划分为pointNum*2步,前pointNum步是各个点依次飞入,后pointNum步是各个点依次飞出。根据动画当前执行到哪一步去计算点的位置。

  把点的位置又分为三个部分——enterX, transX, exitX,分别代表飞入距离、平移距离、飞出距离。根据动画当前执行到哪一步分别计算。在计算飞入距离和飞出距离时利用补差器去让运动更加平滑。

源码

[code]package com.example.myronlg.windowsstyleloadingdemo;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * Created by myron.lg on 2015/7/9.
 */
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;

    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<>(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<>();
        for (int i = 0; i < pointNum; i++) {
            paints.add(new Paint(paint));
        }

        enterInterpolator = new DecelerateInterpolator(1.5F);
        exitInterpolator = new AccelerateInterpolator(2.0F);

        duration = 600;
    }

    @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));
        }

        update();
    }

    private void update(){
        long currentMillis = System.currentTimeMillis();
        if (startMillis == -1){
            startMillis = currentMillis;
        }

        // (pointNum * 2 * duration) is a cycle
        long passMills = (currentMillis - startMillis) % (pointNum * 2 * duration);

        // update 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 = 0;
            float transX = 0;
            float exitX = 0;

            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);
        }
        invalidate();
    }
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: