Android——自定义View(二)

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();
	    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值