美文网首页
Android——自定义View(二)

Android——自定义View(二)

作者: 如愿以偿丶 | 来源:发表于2019-09-29 21:58 被阅读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();
            }
    

    相关文章

      网友评论

          本文标题:Android——自定义View(二)

          本文链接:https://www.haomeiwen.com/subject/zwvqpctx.html