Android仿58同城Loading View

今天打开58同城App看到他们的网络加载Loading做的很有新意,是一个三角形,圆形,正方形不同的运动并且切换,这个效果不说有多难,至少很有创意,就着手模仿了一下,先看下效果图:
Android仿58同城Loading View_第1张图片
58的更加复杂,在形状运动的过程还一直不停的旋转,旋转的坐标计算太复杂, 还没有搞定,先把这个半成品开源出来。

思路:1.先画一个静态的形状和下面的阴影。  
     2.通过ValueAnimator不停的改变纵坐标,在动画的监听中拿到 当前的坐标值,重新invalidate()此时的View。
     3.在向下的动画执行完毕后,更新Shape。然后让动画不停的运动即可。
package view;
/**
 * @description 仿58加载View
 * @author rzq
 * @date 2015年10月10日
 */
public class MyLoadingView extends View
{
    /**
     * 公共变量
     */
    private Context mContext;
    private Resources mResource;
    private Paint mPaint;
    private Paint mOvalPaint;
    /**
     */
    private int mRadius;
    private int mDistance;
    private int mOvalTop;
    private int mOvalHeight;
    private int mOvalWidth;

    /**
     * 所有形状的中心位置
     */
    private int mCenterX, mCenterY;
    private int currentCenterY;
    private Animator mRotationAnim;
    private ValueAnimator mLineAnimDown;
    private ValueAnimator mLineAnimUp;
    private Shape shape;

    public MyLoadingView(Context context)
    {
        this(context, null);
    }

    public MyLoadingView(Context context, AttributeSet attrs)
    {
        super(context);
        this.mContext = context;
        this.mResource = context.getResources();
        init();
    }

    private void init()
    {
        mRadius = 10;
        mDistance = 50;
        mOvalHeight = 3;
        mOvalWidth = 10;
        mOvalTop = 25;

        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setStyle(Style.FILL);
        mPaint.setColor(mResource.getColor(R.color.rect));

        mOvalPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mOvalPaint.setStyle(Style.FILL);
        mOvalPaint.setColor(mResource.getColor(R.color.color_666666));

        setupAnimations();
        shape = Shape.RECT;

    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
    {
        /**
         * 宽度最长是矩形的宽,高度最高是矩形的高加上distance
         */
        int width = (mRadius * 2);
        int height = (mDistance + mRadius * 2 + mOvalTop + mOvalHeight);
        setMeasuredDimension(width, height);
        currentCenterY = mCenterX = mCenterY = mRadius;
    }

    @Override
    protected void onDraw(Canvas canvas)
    {
        switch (shape)
        {
        case RECT:
            drawRect(canvas);
            break;
        case TRAIL:
            drawTrail(canvas);
            break;
        case CIRCLE:
            drawCircle(canvas);
            break;
        }

        drawOval(canvas);
    }

    /**
     * 更具中心点的改变,绘制矩形
     */
    private void drawRect(Canvas canvas)
    {
        canvas.drawRect(mCenterX - mRadius, currentCenterY - mRadius, mCenterX + mRadius, currentCenterY + mRadius,
                mPaint);
    }

    private void drawTrail(Canvas canvas)
    {
        Path path = new Path();
        int leftX = 0;
        int leftY = currentCenterY + mRadius;
        int middleX = mCenterX;
        int middleY = currentCenterY - mRadius;
        int rightX = mCenterX + mRadius;
        int rightY = currentCenterY + mRadius;
        path.moveTo(leftX, leftY);
        path.lineTo(middleX, middleY);
        path.lineTo(rightX, rightY);
        path.close();
        canvas.drawPath(path, mPaint);
    }

    private void drawCircle(Canvas canvas)
    {
        canvas.drawCircle(mCenterX, currentCenterY, mRadius, mPaint);
    }

    private void drawOval(Canvas canvas)
    {
        float factory = ((mDistance + mRadius) - currentCenterY) / (float) mDistance;
        RectF rectF = new RectF(mCenterX - mOvalWidth * factory, mDistance + mRadius * 2 + mOvalTop, mCenterX
                + mOvalWidth * factory, mDistance + mRadius * 2 + mOvalTop + mOvalHeight);
        canvas.drawOval(rectF, mOvalPaint);
    }

    private void setupAnimations()
    {
        mRotationAnim = ValueAnimator.ofInt(0, 180);

        mLineAnimDown = ValueAnimator.ofInt(mCenterY + mRadius, mDistance);
        mLineAnimDown.setInterpolator(new AccelerateInterpolator(1.2f));
        mLineAnimDown.addUpdateListener(new ValueAnimator.AnimatorUpdateListener()
        {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator)
            {
                currentCenterY = (Integer) valueAnimator.getAnimatedValue();
                invalidate();
            }
        });

        mLineAnimUp = ValueAnimator.ofInt(mDistance, mCenterY + mRadius);
        mLineAnimUp.setInterpolator(new DecelerateInterpolator(1.2f));
        mLineAnimUp.addUpdateListener(new ValueAnimator.AnimatorUpdateListener()
        {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator)
            {
                currentCenterY = (Integer) valueAnimator.getAnimatedValue();
                invalidate();
            }
        });

        mLineAnimDown.addListener(new AnimatorListenerAdapter()
        {
            @Override
            public void onAnimationEnd(Animator animation)
            {
                if (shape == Shape.RECT)
                {
                    mPaint.setColor(mResource.getColor(R.color.triangle));
                    shape = Shape.TRAIL;
                }
                else
                {
                    if (shape == Shape.TRAIL)
                    {

                        mPaint.setColor(mResource.getColor(R.color.circle));
                        shape = Shape.CIRCLE;
                    }
                    else
                    {
                        mPaint.setColor(mResource.getColor(R.color.rect));
                        shape = Shape.RECT;
                    }
                }
            }
        });

        final AnimatorSet set = new AnimatorSet();
        set.addListener(new AnimatorListener()
        {
            @Override
            public void onAnimationStart(Animator animation)
            {
            }

            @Override
            public void onAnimationRepeat(Animator animation)
            {
            }

            @Override
            public void onAnimationEnd(Animator animation)
            {
                set.start();
            }

            @Override
            public void onAnimationCancel(Animator animation)
            {
            }
        });
        set.playSequentially(mLineAnimDown, mLineAnimUp);
        set.setDuration(300);
        set.setStartDelay(100);
        set.start();
    }

    private enum Shape
    {
        RECT, TRAIL, CIRCLE;
    }
}

用法:直接在布局中引入即可。
     "http://schemas.android.com/apk/res
     /android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
     xmlns:tools="http://schemas.android.com/tools"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:background="@android:color/white" >

    "@+id/loadView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true" />

之前看到一个开源View整个动画都是用ViewAnimator衔接起来的,感觉这种方式非常的好,我也尝试的用这种方式实现。

扩张:自定义 View中我为方便将一些属性等的都直接指定了,更好的方式是以自定义属性的方式使用更好。

![欢迎大家关注我的微信公众号,每天会为大家推荐一篇好的技术文章,还有我的视频课程喔](https://img-blog.csdn.net/20160927222837538)

你可能感兴趣的:(andorid,应用程序,自定义View)