Android——自定义View(二)

2019-09-29  本文已影响0人  如愿以偿丶

1.效果展示

              在这里插入图片描述

2.效果分析

  1.绘制6个不同颜色的圆
  2.通过属性动画不断改变每个圆的旋转角度进行旋转
  3.旋转动画结束后不断改变大圆的半径将聚合到中间
  4.聚合动画结束后在绘制一个圆,不断增大圆的半径
在这里插入图片描述

3.效果实现

  3.1.绘制6个不同颜色的圆,并开启旋转动画
    public class LoadingView extends View {
        private final String TAG = "LoadingView";
        //是否初始化参数
        private boolean mInitParams = false;
        //动画旋转时间
        private final long ROTATION_ANIMATION_TIME = 2500;
        //当前大圆旋转的角度(弧度)
        private float mCurrentRotationAngle = 0F;
        //小圆颜色列表
        private int[] mCircleColors;
        //外圈大圆的半径,整个屏幕宽度的 1/4 半径的圆心是以屏幕左上角为中心,所以我们需要设置中心点
        private int mRotationRadius;
        //小圆半径时大圆半径的 1/8;
        private int mCircleRadius;
        //小圆画笔
        private Paint mPaint;
        //屏幕中心点
        private int mCenterX,mCenterY;
        //整体颜色背景
        private int mSplashColor = Color.WHITE;
        //代表当前状态所画动画
        private LoadingState mLoadingState;
        //获取当前大圆的半径
        private float mCurrentRotationRadius;
        //最后一步 空心圆初始半径
        private float mHoleRadius = 0f;
        //对角线的一半大小
        private float mDiagonalDist;
        //优化设置标记
        private boolean isStopAnimator = false;
       
        public LoadingView(Context context) {
            this(context,null);
        }
    
        public LoadingView(Context context, @Nullable AttributeSet attrs) {
            this(context, attrs,0);
        }
    
        public LoadingView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            if (!mInitParams){
                //初始化获取宽高等信息
                initParams();
            }
    
            if (mLoadingState == null){
                mLoadingState = new RotationState();
            }
            //绘制我们的小圆,通过属性动画进行旋转
            mLoadingState.draw(canvas);
    
        }
    
        private void initParams() {
           //获取小圆的颜色数组
            mCircleColors = getContext().getResources().getIntArray(R.array.splash_circle_colors);
            //外围大圆的半径 = 屏幕宽度 / 4
            mRotationRadius = getMeasuredWidth() / 4;
            //旋转小圆的半径 = 大圆半径 / 8;
            mCircleRadius = mRotationRadius / 8;
            mCenterX = getMeasuredWidth() / 2;
            mCenterY = getMeasuredHeight() / 2;
            mDiagonalDist = (float) Math.sqrt(getMeasuredHeight() * getMeasuredHeight() + getMeasuredWidth() * getMeasuredWidth());
            mPaint = new Paint();
            mPaint.setAntiAlias(true);
            mPaint.setDither(true);
            mInitParams = true;
        }
    
        /**
         * 动画消失,开始聚合,将我们代码进行封装
         */
        public void disappear() {
            if (isStopAnimator){
                return;
            }
            //关闭旋转动画
            if (mLoadingState instanceof RotationState){
                RotationState rotationState = (RotationState) mLoadingState;
                rotationState.cancel();
            }
            //开启我们聚合动画
            mLoadingState = new MergeState();
        }


        //将我们三个动画进行封装,便于维护
        public abstract class LoadingState{
            public abstract void draw(Canvas canvas);
        }
    
        /**
         * 旋转动画和绘制
         */
        public class RotationState extends LoadingState{
            private ValueAnimator mAnimation;
            /**
             * 为什么不旋转?
             *  当我们每次onDraw的时候都会创建一个animator,每次都从0开始,将animator提为全局
             */
            public RotationState(){
                //搞一个变量不断 去改变采用属性动画 旋转0-360
                mAnimation = ObjectAnimator.ofFloat(0F,2F * (float) Math.PI);
                mAnimation.setDuration(ROTATION_ANIMATION_TIME);
                mAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                     @Override
                     public void onAnimationUpdate(ValueAnimator mAnimation) {
                     //动画监听
                     mCurrentRotationAngle = (float) mAnimation.getAnimatedValue();
                         Log.e(TAG,"旋转动画1111111111");
                     //重新绘制
                     invalidate();
                     }
                });
                //匀速插值器
                mAnimation.setInterpolator(new LinearInterpolator());
                //不断反复执行
                mAnimation.setRepeatCount(-1);
                mAnimation.start();
            }
    
            @Override
            public void draw(Canvas canvas) {
                canvas.drawColor(mSplashColor);
                //画六个圆  获取每个圆的角度
                double percentAngle = 2 * Math.PI / mCircleColors.length;
                for (int i = 0; i < mCircleColors.length; i++) {
                    //设置每一个圆画笔的颜色
                    mPaint.setColor(mCircleColors[i]);
                    // 当前角度 = 每份角度 + 旋转角度
                    double currentAngle = percentAngle * i + mCurrentRotationAngle;
                    // 通过公式计算
                    float cx = (float) (mCenterX + mRotationRadius * Math.cos(currentAngle));
                    float cy = (float) (mCenterY + mRotationRadius * Math.sin(currentAngle));
                    canvas.drawCircle(cx,cy,mCircleRadius,mPaint);
                }
            }
    
            /**
             * 关闭动画
             */
            public void cancel() {
                mAnimation.cancel();
            }
        }
    }
  3.2.开启我们的聚合动画
     /**
     * 聚合动画
     */
    public class MergeState extends LoadingState{
        private ValueAnimator mAnimation;
        public MergeState(){
            //不断平移动画,减小我们大圆半径就可以,刚开始有一个插值器,先往后跑,在往中间聚合
            mAnimation = ObjectAnimator.ofFloat(mRotationRadius,0);
            mAnimation.setDuration(ROTATION_ANIMATION_TIME / 2);
            mAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator mAnimation) {
                    //动画监听
                    mCurrentRotationRadius = (float) mAnimation.getAnimatedValue();
                    //重新绘制
                    invalidate();
                    Log.e(TAG,"合并动画222222222");
                }
            });
            mAnimation.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    mAnimation.cancel();
                    mLoadingState = new ExpendState();
                }
            });

            //匀速插值器
            mAnimation.setInterpolator(new AnticipateInterpolator(5f));
            mAnimation.start();
        }

        @Override
        public void draw(Canvas canvas) {
            canvas.drawColor(mSplashColor);
            //画六个圆  获取每个圆的角度
            double percentAngle = 2 * Math.PI / mCircleColors.length;
            for (int i = 0; i < mCircleColors.length; i++) {
                //设置每一个圆画笔的颜色
                mPaint.setColor(mCircleColors[i]);
                // 当前角度 = 每份角度 + 旋转角度
                double currentAngle = percentAngle * i + mCurrentRotationAngle;
                // 通过公式计算
                float cx = (float) (mCenterX + mCurrentRotationRadius * Math.cos(currentAngle));
                float cy = (float) (mCenterY + mCurrentRotationRadius * Math.sin(currentAngle));
                canvas.drawCircle(cx,cy,mCircleRadius,mPaint);
            }
        }
    }
  3.3.聚合动画结束后在绘制一个圆,不断增大圆的半径
    /**
     * 展开动画
     */
    public class ExpendState extends LoadingState{
        private ValueAnimator mAnimation;
        public ExpendState(){
            //从屏幕中心点开始扩散,不断改变圆的半径大小,最终半径为屏幕对角线的一般
            mAnimation = ObjectAnimator.ofFloat(mHoleRadius,mDiagonalDist);
            mAnimation.setDuration(ROTATION_ANIMATION_TIME / 2);
            mAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator mAnimation) {
                    //动画监听
                    mHoleRadius = (float) mAnimation.getAnimatedValue();
                    Log.e(TAG,"扩散动画33333333333");
                    //重新绘制
                    invalidate();
                }
            });
            mAnimation.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    loadEndListener.loadEnd();
                }
            });
            mAnimation.start();
        }
        @Override
        public void draw(Canvas canvas) {
            //画笔的宽度
            float strokeWidth = mDiagonalDist - mHoleRadius;
            mPaint.setStyle(Paint.Style.STROKE);
            mPaint.setStrokeWidth(strokeWidth);
            mPaint.setColor(mSplashColor);
            //此时圆心就是屏幕的中心点
            float cx = (float) mCenterX;
            float cy = (float) mCenterY;
            //注意圆的半径
            float radius = strokeWidth / 2 + mHoleRadius;
            canvas.drawCircle(cx,cy,radius,mPaint);
        }
    }

4.最后优化

  1.当我们网络请求结束后,将我们的View设置为INVISIBLE,减少布局的测量和摆放,减少系统的View的绘制流程
  2.清除我们的动画
  3.设置一个标志位,通过标志来判断是否需要执行动画
  4.判断我们父容器是否存在,把自己移除

        @Override
        public void setVisibility(int visibility) {
            //1.将我们的View设置为INVISIBLE,减少布局的测量和摆放,减少系统的View的绘制流程
            super.setVisibility(INVISIBLE);
            //2.清除我们的动画
            clearAnimation();
            //3.设置一个标志位,通过标志位来执行动画
            isStopAnimator = true;
            //4.判断父容器是否还在,把自己移除,清除自己的所有View
            ViewGroup parent = (ViewGroup) getParent();
            if (parent!=null){
                //把自己从父容器移除
                parent.removeView(this);
                //移除自己的所有子View
                this.removeAllViews();
        }
上一篇下一篇

猜你喜欢

热点阅读