Android 自定义view开发caseandroid之道

一个非常漂亮的自定义Loading,有加载成功和失败两种状态。

2016-07-14  本文已影响4241人  hadisi5216
这还只是张图片

本文原创,这篇可不能匿名转载。

背景:我一哥们公司做智能设备的,该动画用在手机和家中网络连接时用,他让我看了下需求。刚看到这动画时感觉产品\UI设计的不错,想着试试。昨天开始做的,本来感觉很简单,但做起来貌似没那么简单;最后花了近一天时间终于搞定了。看看效果还行!

niceloading.gif

1.直接上代码(NiceLoadingView)

package com.hadisi.niceloading;

import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.LinearInterpolator;

/**
 * Created by hadisi5216 on 2016/7/12.
 */

public class NiceLoadingView extends View {

    private Context mContext;
    private Paint mPaint;

    private int widthSpecSize;
    private int heightSpecSize;
    private int radiusSmall = 38;
    private int radiusbig = 76;
    private int moveX;
    private int XPoint;

    private int mState = -1;//0失败,1成功,-1默认
    private boolean mflag;

    private ValueAnimator animator;

    public NiceLoadingView(Context context) {
        super(context);
    }

    public NiceLoadingView(Context context, AttributeSet attrs) {
        super(context, attrs);

    }

    public NiceLoadingView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mContext = context;
        mPaint = new Paint();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
        heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        mPaint.setColor(0xFFFFBC53);
        mPaint.setAntiAlias(true);
        if (Math.abs(moveX) > widthSpecSize * 5 / 4) {
            XPoint = (moveX < 0) ? XPoint = widthSpecSize * 7 / 4 - Math.abs(moveX) : widthSpecSize - widthSpecSize * 7 / 4 + Math.abs(moveX);
            canvas.drawCircle(XPoint, heightSpecSize / 2, radiusSmall, mPaint);
        }
        if (Math.abs(moveX) > widthSpecSize && Math.abs(moveX) < widthSpecSize * 3 / 2) {
            XPoint = (moveX < 0) ? XPoint = widthSpecSize * 3 / 2 - Math.abs(moveX) : widthSpecSize - widthSpecSize * 3 / 2 + Math.abs(moveX);
            canvas.drawCircle(XPoint, heightSpecSize / 2, radiusSmall, mPaint);
        }
        if (Math.abs(moveX) > widthSpecSize * 3 / 4 && Math.abs(moveX) < widthSpecSize * 5 / 4) {
            XPoint = (moveX < 0) ? XPoint = widthSpecSize * 5 / 4 - Math.abs(moveX) : widthSpecSize - widthSpecSize * 5 / 4 + Math.abs(moveX);
            canvas.drawCircle(XPoint, heightSpecSize / 2, radiusSmall, mPaint);
        }
        if (Math.abs(moveX) > widthSpecSize / 2 && Math.abs(moveX) < widthSpecSize) {
            XPoint = (moveX < 0) ? XPoint = widthSpecSize - Math.abs(moveX) : widthSpecSize - widthSpecSize + Math.abs(moveX);
            canvas.drawCircle(XPoint, heightSpecSize / 2, radiusSmall, mPaint);
        }
        if (Math.abs(moveX) > widthSpecSize / 4 && Math.abs(moveX) < widthSpecSize * 3 / 4) {
            XPoint = (moveX < 0) ? XPoint = widthSpecSize * 3 / 4 - Math.abs(moveX) : widthSpecSize - widthSpecSize * 3 / 4 + Math.abs(moveX);
            canvas.drawCircle(XPoint, heightSpecSize / 2, radiusSmall, mPaint);
        }
        if (Math.abs(moveX) > 0 && Math.abs(moveX) < widthSpecSize / 2) {
            XPoint = (moveX < 0) ? XPoint = widthSpecSize / 2 - Math.abs(moveX) : widthSpecSize - widthSpecSize / 2 + Math.abs(moveX);
            canvas.drawCircle(XPoint, heightSpecSize / 2, radiusSmall, mPaint);
        }
        //中间大圆
        if (Math.abs(moveX) > 0 && Math.abs(moveX) < widthSpecSize * 5 / 4) {
            radiusbig = 2 * radiusSmall - radiusSmall * (Math.abs(moveX)) / (widthSpecSize * 5 / 4);
            radiusbig = (radiusbig > radiusSmall) ? radiusbig : radiusSmall;
            canvas.drawCircle(widthSpecSize / 2, heightSpecSize / 2, radiusbig, mPaint);
        }
        if (Math.abs(moveX) < 12 && mState >= 0) {
            if (mState == 0) {
                canvas.drawCircle(widthSpecSize / 2, heightSpecSize / 2, radiusbig, mPaint);
                Bitmap bitmap = BitmapFactory.decodeResource(getContext().getResources(), R.mipmap.connect_failed);
                canvas.drawBitmap(bitmap, null, new Rect(widthSpecSize / 2 - radiusbig, heightSpecSize / 2 - radiusbig, widthSpecSize / 2 + radiusbig, heightSpecSize / 2 + radiusbig), mPaint);
            }
            if (mState == 1) {
                canvas.drawCircle(widthSpecSize / 2, heightSpecSize / 2, radiusbig, mPaint);
                Bitmap bitmap = BitmapFactory.decodeResource(getContext().getResources(), R.mipmap.connect_success);
                canvas.drawBitmap(bitmap, null, new Rect(widthSpecSize / 2 - radiusbig, heightSpecSize / 2 - radiusbig, widthSpecSize / 2 + radiusbig, heightSpecSize / 2 + radiusbig), mPaint);
            }
        }
    }

    public void start() {
        if (animator != null)
            animator.cancel();
        moveX = widthSpecSize * (-9 / 4);
        mState = -1;
        mflag = true;
        post(new Runnable() {
            @Override
            public void run() {
                animator = ValueAnimator.ofFloat(0f, 1.0f);
                animator.setRepeatMode(ValueAnimator.RESTART);
                animator.setRepeatCount(ValueAnimator.INFINITE);
                animator.setInterpolator(new LinearInterpolator());
                animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                    @Override
                    public void onAnimationUpdate(ValueAnimator animation) {
                        if (mState < 0) {
                            moveX = (moveX > widthSpecSize * 7 / 4) ? widthSpecSize * (-9 / 4) : moveX + 12;
                        } else {
                            if (moveX > 0)
                                moveX = (moveX > widthSpecSize * 7 / 4) ? widthSpecSize * (-9 / 4) : moveX + 12;
                            else if (moveX < 0 && mflag) {
                                moveX += 12;
                                if (Math.abs(moveX) < 12)
                                    mflag = false;
                            }
                        }
                        postInvalidate();
                    }
                });
                animator.start();
            }
        });
    }

    public void success() {
        mState = 1;
    }

    public void failed() {
        mState = 0;
    }
}

项目已上传到github,戳着

2.怎么用?

<com.hadisi.niceloading.NiceLoadingView
            android:id="@+id/nice_loading"
            android:layout_width="match_parent"
            android:layout_height="100dp" />
NiceLoadingView niceLoading = (NiceLoadingView) findViewById(R.id.nice_loading);
……
//开始连接时
niceLoading.start();
……
//连接成功时
niceLoading.success();
……
//连接失败时
niceLoading.failed();

3.我怎么实现的!

仔细看效果图可以得出:
1、有6个小圆依次从屏幕左侧移入屏幕中间,然后又依次从屏幕中间移出屏幕右侧。
2、中间有个大圆在随着小圆的依次靠近慢慢变大,离开慢慢变小;注意在左侧第1个小圆到达中间时才出现大圆,在最后一个小圆准备向右侧移动时消失;大圆的半径在小圆半径和大圆半径之间。
3、不管何时得到成功和失败的状态,动画终止时都是在小圆依次从左边进入中间后。
4、动画完成后显示成功/失败图片和大圆。

自己画的图,有点丑

对照图很快可以得出下面代码

if (Math.abs(moveX) > widthSpecSize * 5 / 4) {
    XPoint = (moveX < 0) ? XPoint = widthSpecSize * 7 / 4 - Math.abs(moveX) : widthSpecSize - widthSpecSize * 7 / 4 + Math.abs(moveX);
    canvas.drawCircle(XPoint, heightSpecSize / 2, radiusSmall, mPaint);
}
if (Math.abs(moveX) > widthSpecSize && Math.abs(moveX) < widthSpecSize * 3 / 2) {
    XPoint = (moveX < 0) ? XPoint = widthSpecSize * 3 / 2 - Math.abs(moveX) : widthSpecSize - widthSpecSize * 3 / 2 + Math.abs(moveX);
    canvas.drawCircle(XPoint, heightSpecSize / 2, radiusSmall, mPaint);
}
if (Math.abs(moveX) > widthSpecSize * 3 / 4 && Math.abs(moveX) < widthSpecSize * 5 / 4) {
    XPoint = (moveX < 0) ? XPoint = widthSpecSize * 5 / 4 - Math.abs(moveX) : widthSpecSize - widthSpecSize * 5 / 4 + Math.abs(moveX);
    canvas.drawCircle(XPoint, heightSpecSize / 2, radiusSmall, mPaint);
}
if (Math.abs(moveX) > widthSpecSize / 2 && Math.abs(moveX) < widthSpecSize) {
    XPoint = (moveX < 0) ? XPoint = widthSpecSize - Math.abs(moveX) : widthSpecSize - widthSpecSize + Math.abs(moveX);
    canvas.drawCircle(XPoint, heightSpecSize / 2, radiusSmall, mPaint);
}
if (Math.abs(moveX) > widthSpecSize / 4 && Math.abs(moveX) < widthSpecSize * 3 / 4) {
    XPoint = (moveX < 0) ? XPoint = widthSpecSize * 3 / 4 - Math.abs(moveX) : widthSpecSize - widthSpecSize * 3 / 4 + Math.abs(moveX);
    canvas.drawCircle(XPoint, heightSpecSize / 2, radiusSmall, mPaint);
}
if (Math.abs(moveX) > 0 && Math.abs(moveX) < widthSpecSize / 2) {
    XPoint = (moveX < 0) ? XPoint = widthSpecSize / 2 - Math.abs(moveX) : widthSpecSize - widthSpecSize / 2 + Math.abs(moveX);
    canvas.drawCircle(XPoint, heightSpecSize / 2, radiusSmall, mPaint);
}
if (Math.abs(moveX) > 0 && Math.abs(moveX) < widthSpecSize * 5 / 4) {
    radiusbig = radiusbig - radiusSmall * (Math.abs(moveX)) / (widthSpecSize * 5 / 4);
    radiusbig = (radiusbig > radiusSmall) ? radiusbig : radiusSmall;
    canvas.drawCircle(widthSpecSize / 2, heightSpecSize / 2, radiusbig, mPaint);
}
if (mState < 0) {
    moveX = (moveX > widthSpecSize * 7 / 4) ? widthSpecSize * (-9 / 4) : moveX + 12;
} else {
    if (moveX > 0)
        moveX = (moveX > widthSpecSize * 7 / 4) ? widthSpecSize * (-9 / 4) : moveX + 12;
    else if (moveX < 0 && mflag) {
        moveX += 12;
        if (Math.abs(moveX) < 12)
            mflag = false;
    }
}
if (Math.abs(moveX) < 12 && mState >= 0) {
            if (mState == 0) {
                canvas.drawCircle(widthSpecSize / 2, heightSpecSize / 2, radiusbig, mPaint);
                Bitmap bitmap = BitmapFactory.decodeResource(getContext().getResources(), R.mipmap.connect_failed);
                canvas.drawBitmap(bitmap, null, new Rect(widthSpecSize / 2 - radiusbig, heightSpecSize / 2 - radiusbig, widthSpecSize / 2 + radiusbig, heightSpecSize / 2 + radiusbig), mPaint);
            }
            if (mState == 1) {
                canvas.drawCircle(widthSpecSize / 2, heightSpecSize / 2, radiusbig, mPaint);
                Bitmap bitmap = BitmapFactory.decodeResource(getContext().getResources(), R.mipmap.connect_success);
                canvas.drawBitmap(bitmap, null, new Rect(widthSpecSize / 2 - radiusbig, heightSpecSize / 2 - radiusbig, widthSpecSize / 2 + radiusbig, heightSpecSize / 2 + radiusbig), mPaint);
            }
        }

4.优化

其实核心的就是想法,随便怎么优化。反正我就弄到这了,油而不腻,我觉得挺好,不需要太多优化。吼吼....

上一篇 下一篇

猜你喜欢

热点阅读