自定义雅虎新闻闪屏加载动画

activity的绘制

闪屏的原理是画两层view,一层就是动画结束需要呈现的底层,我们这里定义为ContentView,另外一层就是我们的动画SplashView,动画都在这层上绘制,
在activity这里我们先画contentView,再画SplashView,这样SplashView就在contentView的上层,清除SplashView就可以显示contentView

   public class SplanshActivity extends Activity {//AppCompat

    private FrameLayout fragment;
    private SplashView splashView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_splansh);
        fragment = new FrameLayout(this);
        ContentView contentView = new ContentView(this);
        fragment.addView(contentView);
         splashView = new SplashView(this);
        fragment.addView(splashView);
        setContentView(fragment);
        //开始加载数据
        startSplanshDataLoad();
    }

    Handler handler = new Handler();

    private void startSplanshDataLoad() {
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                //数据加载完毕--进入主界面--开启后面两个动画
                splashView.SplashDisappear();
            }
        }, 2000);
    }
}

contentView

contentView没有什么特别之处,我们用imageView演示就可以了

public class ContentView extends ImageView{
    public ContentView(Context context) {
        super(context);
        setImageResource(R.drawable.a1);
    }
}

splashView

所有的动画都在这层

我们的动画分三部分:
- 小球旋转加载
- 小球聚合
- 空心圆扩散

不使用ifelse来写,使用状态模式这种设计模式,好处不言而喻

 private SplashState mState = null;

    private abstract class SplashState {
        public abstract void drawState(Canvas canvas);

    }

用mState对象来保存当前执行的动画,写一个内部类或者接口,来规范我们的状态行为

public class SplashView extends View {
    /**
     * some adjustable paramerters
     **/
    //大圆(里面包括很多小圆)的半径
    private float mRoatationRadius = 90;
    //每个小圆的半径
    private float mCircleRadius = 18;
    //小圆圈颜色列表,在initiallize方法里面初始化
    private int[] mCircleColors;
    //大圆和小圆旋转的时间
    private long mRoatationDuration = 1200;//ms
    //第二部分动画的总执行时间(包第二个动画时间,各占用1/2)

    private long mSplashDuration = 1200;//ms
    //整体的背景颜色
    private int mSplashBgColor = Color.WHITE;//ms
    /**
     * 参数,保存一些绘制的状态,会被动态地改变
     */
    //空心圆初始半径
    private float mHoleRadius = 0F;
    //当前大圆旋转角度(弧度)
    private float mCurrentRotationAngle = 0F;
    //当前大圆的半径
    private float mCurrentRotationRadius = mRoatationRadius;
    //绘制圆的画笔

    private Paint mPaint = new Paint();
    //绘制背景的画笔
    private Paint mPaintBackground = new Paint();
    //屏幕正中心点坐标
    private float mCenterX;
    private float mCenterY;
    //屏幕对角线一半
    private float mDiagonalDist;

    public SplashView(Context context) {
        super(context);
        init();
    }

    private void init() {
        mPaint.setAntiAlias(true);
        mPaintBackground.setAntiAlias(true);
        mPaintBackground.setStyle(Paint.Style.STROKE);
        mPaintBackground.setColor(mSplashBgColor);
        mCircleColors = getContext().getResources().getIntArray(R.array.splash_circle_colors);
    }


    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mCenterX = w / 2f;
        mCenterY = h / 2f;
        mDiagonalDist = (float) Math.sqrt(w * w + h * h) / 2;
    }

    public void SplashDisappear() {
        //进入主页面 开启后面的两个动画
        if (mState != null && mState instanceof RotationState) {
            RotationState rotationState = (RotationState) mState;
            rotationState.cancel();
            post(new Runnable() {
                @Override
                public void run() {
                    //状态修改
                    mState = new MergingState();
                }
            });

//            invalidate();
        }
    }

    //保存当前动画状态--当前在执行哪种动画
    private SplashState mState = null;

    private abstract class SplashState {
        public abstract void drawState(Canvas canvas);

    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //绘制动画,三种状态
        if (mState == null) {
            //默认加载第一个
            mState = new RotationState();
            Log.i("wxh", "执行了");
        }
        //绘制的分发
        mState.drawState(canvas);
    }

    /**
     * 小球旋转动画
     */
    private class RotationState extends SplashState {
        private ValueAnimator animator;

        public RotationState() {
            //小圆的坐标-->大圆的旋转读书(0~2π)、半径
            animator = ValueAnimator.ofFloat(0, (float) Math.PI * 2);
            //设置线性插值器---平滑计算
            animator.setInterpolator(new LinearInterpolator());
            //计算时间
            animator.setDuration(mRoatationDuration);
            //设置监听
            animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    //不断修改旋转的角度
                    mCurrentRotationAngle = (float) animation.getAnimatedValue();
//                    Log.i("wxh",mCurrentRota);
                    //提醒view重新绘制onDraw
                    invalidate();
                }
            });
            //循环次数为无限
            animator.setRepeatCount(ValueAnimator.INFINITE);
            animator.start();
            Log.i("wxh", "cccc");
        }

        public void cancel() {
            animator.cancel();
        }

        @Override
        public void drawState(Canvas canvas) {
            //绘制背景(还原纯色)
            drawBackground(canvas);
            //绘制小圆
            drawCircle(canvas);
        }

        private void drawCircle(Canvas canvas) {

            //绘制小圆(坐标、自身半径)核心算法哦
            //得到每个小圆中间的间隔角度
            float rotationAngle = (float) (2 * Math.PI / mCircleColors.length);
            for (int i = 0; i < mCircleColors.length; i++) {
                /**
                 * x=r*cos(a)
                 * y=r*sin(a)
                 */
                double angle = i * rotationAngle + mCurrentRotationAngle;
                float cx = (float) (mCurrentRotationRadius * Math.cos(angle) + mCenterX);
                float cy = (float) (mCurrentRotationRadius * Math.sin(angle) + mCenterY);
                mPaint.setColor(mCircleColors[i]);
                canvas.drawCircle(cx, cy, mCircleRadius, mPaint);
            }
        }

        private void drawBackground(Canvas canvas) {
            //擦黑板
            canvas.drawColor(mSplashBgColor);
        }
    }

    /**
     * 小球聚合动画
     */
    private class MergingState extends SplashState {
        private ValueAnimator animator;

        public MergingState() {
            //小圆的坐标-->大圆的旋转读书(0~2π)、半径
            animator = ValueAnimator.ofFloat(0, mRoatationRadius);
            //设置线性插值器---弹射效果
            animator.setInterpolator(new OvershootInterpolator(10f));
            //计算时间
            animator.setDuration(mSplashDuration / 2);//++
            //设置监听
            animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    //不断修改大圆半径
                    mCurrentRotationRadius = (Float) animation.getAnimatedValue();
//                    Log.i("wxh",mCurrentRota);
                    //提醒view重新绘制onDraw
                    postInvalidate();
                }
            });
            animator.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    super.onAnimationEnd(animation);
                    //开启下一个动画
                    mState = new ExpandingState();
                }
            });
            //反向计算
            animator.reverse();
        }

        @Override
        public void drawState(Canvas canvas) {
            //绘制背景(还原纯色)
            drawBackground(canvas);
            //绘制小圆
            drawCircle(canvas);
        }

        private void drawCircle(Canvas canvas) {

            //绘制小圆(坐标、自身半径)核心算法哦
            //得到每个小圆中间的间隔角度
            float rotationAngle = (float) (2 * Math.PI / mCircleColors.length);
            for (int i = 0; i < mCircleColors.length; i++) {
                /**
                 * x=r*cos(a)
                 * y=r*sin(a)
                 */
                double angle = i * rotationAngle + mCurrentRotationAngle;
                float cx = (float) (mCurrentRotationRadius * Math.cos(angle) + mCenterX);
                float cy = (float) (mCurrentRotationRadius * Math.sin(angle) + mCenterY);
                mPaint.setColor(mCircleColors[i]);
                canvas.drawCircle(cx, cy, mCircleRadius, mPaint);
            }
        }

        private void drawBackground(Canvas canvas) {
            //擦黑板
            canvas.drawColor(mSplashBgColor);
        }
    }

    /**
     * 水波纹的而空心扩散动画
     */
    private class ExpandingState extends SplashState {
        private ValueAnimator animator;

        public ExpandingState() {
            //>计算某个时刻空心圆的半径(0~w*w+h*h开方除二)、半径
            animator = ValueAnimator.ofFloat(0, mDiagonalDist);
            //设置线性插值器---加速器
            animator.setInterpolator(new AccelerateInterpolator());
            //计算时间
            animator.setDuration(mSplashDuration / 2);//++
            //设置监听
            animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    //空心圆当前的半径
                    mHoleRadius = (Float) animation.getAnimatedValue();
//                    Log.i("wxh",mCurrentRota);
                    //提醒view重新绘制onDraw
                    postInvalidate();
                }
            });
            //反向计算
            animator.start();
        }

        @Override
        public void drawState(Canvas canvas) {
            //绘制背景(绘制空心圆背景)
            drawBackground(canvas);
        }

        private void drawBackground(Canvas canvas) {
            if (mHoleRadius > 0f) {
                //画笔的宽度=对角线/2-空心部分的半径
                float strokeWidth = mDiagonalDist - mHoleRadius;
                //绘制空心圆(半径,画笔宽度)
                float radius = mHoleRadius + strokeWidth / 2;
                mPaintBackground.setStrokeWidth(strokeWidth);
                canvas.drawCircle(mCenterX, mCenterY, radius, mPaintBackground);
            } else {
                //擦黑板
                canvas.drawColor(mSplashBgColor);
            }
        }
    }
}

你可能感兴趣的:(Android,android,自定义控件,闪屏)