【android UI学习】简单炫酷Splash界面

先看运行效果

 第一个动画:绘制六个点旋转动画

  • 绘制六个小圆
  1. mCircleColors这里一共是6中颜色,分别对应6个小圆颜色
  2. 每个圆得角度=  2π/小圆的个数
  3. 每个圆得x座标 = 圆半径*cos(a) +圆心X座标
  4. 每个圆得y座标 = 圆半径*sin(a) +圆心Y座标
  5.  每个小圆i*间隔角度 + 旋转的角度 = 当前小圆的真是角度

 六个点得绘制代码

  /**
     * 绘制圆
     * @param canvas
     */
    private void drawCircles(Canvas canvas) {
        //每个小圆得角度     2π/小圆的个数
        double rotationAngle = 2 * Math.PI / mCircleColors.length;

        for (int i = 0; i < mCircleColors.length; i++) {
            /**
             * x = r*cos(a) +centerX
             * y=  r*sin(a) + centerY
             * 每个小圆i*间隔角度 + 旋转的角度 = 当前小圆的真是角度
             */
            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);
        }

    }
  • 六个点得旋转
  1. 动画得改变范围0~2π
  2. 设置动画LinearInterpolator为线性变化
  3. 设置动画状态为ValueAnimator.INFINITE 一直旋转
  4. 通过动态改变偏移角度mCurrentRotationAngle的值,来达到旋转效果
        public RotateState(){
            mAnimator = ValueAnimator.ofFloat(0f,(float)Math.PI*2);
            mAnimator.setInterpolator(new LinearInterpolator());
            mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator valueAnimator) {
                    mCurrentRotationAngle = (float) valueAnimator.getAnimatedValue();
                    Log.d(TAG,"--mCurrentRotationAngle--"+mCurrentRotationAngle);
                    postInvalidate();
                }
            });
            mAnimator.setDuration(mRotationDuration);
            mAnimator.setRepeatCount(ValueAnimator.INFINITE);
            mAnimator.start();
        }

第二个动画:缩放动画

  1.  动态改变这个半径R的值,来达到缩放功能
  2. 动画的取值范围是R到0
  3. 通过动态修改六个圆的绘制半径mCurrentRotationRadius 达到缩放效果
        public MergingState() {
            //花1200ms,计算某个时刻当前的大圆半径是多少? r~0中的某个值
            mAnimator = ValueAnimator.ofFloat(mRotationRadius,0 );
            mAnimator.setDuration(mRotationDuration);
            mAnimator.setInterpolator(new OvershootInterpolator(10f));
            mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator valueAnimator) {
//                    某个时刻当前的大圆半径是多少?
                    mCurrentRotationRadius = (float)valueAnimator.getAnimatedValue();
                    Log.d(TAG,"--mCurrentRotationRadius--"+mCurrentRotationRadius);
                    invalidate();
                }
            });
   
            mAnimator.start();

        }

第三个动画:水波纹扩散动画

  1.  图中R2=屏幕对角线长度/2
  2. R1就是空心圆半径
  3. 画笔的宽度strokeWidth(图中红色部分)  =  R2 - R1
  4. R2是固定大小,我们只需要动态修改R1的大小,就可以动态修改图中红色的面积,我们的demo是设置了白色
            //得到画笔的宽度 = 对角线/2 - 空心圆的半径
            float strokeWidth = mDiagonalDist - mHoleRadius;
            mPaintBackground.setStrokeWidth(strokeWidth);
            //画圆的半径 = 空心圆的半径 + 画笔的宽度/2
            float radius = mHoleRadius + strokeWidth/2;
            canvas.drawCircle(mCenterX,mCenterY,radius,mPaintBackground);

 下面是完整的代码

public class MySplashView extends View {

    private static final String TAG = "MySplashView";
    // 屏幕正中心点座标
    private float mCenterX;
    private float mCenterY;

    //屏幕对角线一半
    private float mDiagonalDist;

    // 小圆圈的颜色列表,在initialize方法里面初始化
    private int[] mCircleColors;

    // 绘制圆的画笔
    private Paint mPaint = new Paint();
    // 绘制背景的画笔
    private Paint mPaintBackground = new Paint();
    // 整体的背景颜色
    private int mSplashBgColor = Color.WHITE;

    private ValueAnimator mAnimator;


    private SplashState mState = null;
    // 大圆(里面包含很多小圆的)的半径
    private float mRotationRadius = 90;

    //当前大圆旋转角度(弧度)
    private float mCurrentRotationAngle = 0F;

    //当前大圆的半径
    private float mCurrentRotationRadius = mRotationRadius;
    // 每一个小圆的半径
    private float mCircleRadius = 18;

    // 大圆和小圆旋转的时间
    private long mRotationDuration = 1200; //ms

    //空心圆初始半径
    private float mHoleRadius = 0F;
    public MySplashView(Context context) {
        super(context);
        init(context);
    }


    public MySplashView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    public MySplashView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }


    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mCenterX = w / 2;
        mCenterY = h / 2;

        mDiagonalDist = (float) ((Math.sqrt(w*w+h*h))/2);

    }

    private void init(Context context) {
        mCircleColors = context.getResources().getIntArray(R.array.splash_circle_colors);
        //画笔初始化
        //消除锯齿
        mPaint.setAntiAlias(true);
        mPaintBackground.setAntiAlias(true);
        //设置样式---边框样式--描边
        mPaintBackground.setStyle(Paint.Style.STROKE);
        mPaintBackground.setColor(mSplashBgColor);
    }


    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if(mState==null){
            //开启第一个旋转动画
            mState = new RotateState();
        }
        mState.drawState(canvas);

    }


    /**
     * 绘制旋转小圆
     * 旋转动画
     */
    private class RotateState extends SplashState{
        public RotateState(){
            mAnimator = ValueAnimator.ofFloat(0f,(float)Math.PI*2);
            mAnimator.setInterpolator(new LinearInterpolator());
            mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator valueAnimator) {
                    mCurrentRotationAngle = (float) valueAnimator.getAnimatedValue();
                    Log.d(TAG,"--mCurrentRotationAngle--"+mCurrentRotationAngle);
                    postInvalidate();
                }
            });
            mAnimator.setDuration(mRotationDuration);
            mAnimator.setRepeatCount(ValueAnimator.INFINITE);
            mAnimator.start();
        }

        @Override
        public void drawState(Canvas canvas) {
            //1.背景--擦黑板,涂成白色
            drawBackground(canvas);
            //2.绘制小圆
            drawCircles(canvas);
        }
    }



    /**
     * 2.聚合动画
     * 要素:大圆的半径不断地变大--变小----》小圆的座标
     */
    private class MergingState extends SplashState{


        public MergingState() {
            //花1200ms,计算某个时刻当前的大圆半径是多少? r~0中的某个值
            mAnimator = ValueAnimator.ofFloat(mRotationRadius,0 );
            mAnimator.setDuration(mRotationDuration);
            mAnimator.setInterpolator(new OvershootInterpolator(10f));
            mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator valueAnimator) {
//                    某个时刻当前的大圆半径是多少?
                    mCurrentRotationRadius = (float)valueAnimator.getAnimatedValue();
                    Log.d(TAG,"--mCurrentRotationRadius--"+mCurrentRotationRadius);
                    invalidate();
                }
            });
            mAnimator.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    super.onAnimationEnd(animation);
                    mState = new ExpandState();
                }
            });
            mAnimator.start();
//            mAnimator.reverse();
        }

        @Override
        public void drawState(Canvas canvas) {
            //1.背景--擦黑板,涂成白色
            drawBackground(canvas);
            //2.绘制小圆
            drawCircles(canvas);
        }
    }


    /**
     * 3.水波纹扩散动画
     * 画一个空心圆----画一个圆,让它的画笔的粗细变成很大---不断地减小画笔的粗细。
     * 空心圆变化的范围:0~ 对角线/2
     */
    private class ExpandState extends SplashState{
        public ExpandState() {
            //花1200ms,计算某个时刻当前的空心圆的半径是多少? r~0中的某个值
            mAnimator = ValueAnimator.ofFloat(mCircleRadius, mDiagonalDist);
            mAnimator.setDuration(mRotationDuration);
            mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator valueAnimator) {
                    //当前的空心圆的半径是多少?
                    mHoleRadius = (float) valueAnimator.getAnimatedValue();
                    invalidate();
                }
            });
            mAnimator.start();
        }

        @Override
        public void drawState(Canvas canvas) {
            drawBackground(canvas);
        }
    }

    private void drawBackground(Canvas canvas) {
        if(mHoleRadius>0f){
            //得到画笔的宽度 = 对角线/2 - 空心圆的半径
            float strokeWidth = mDiagonalDist - mHoleRadius;
            mPaintBackground.setStrokeWidth(strokeWidth);
            //画圆的半径 = 空心圆的半径 + 画笔的宽度/2
            float radius = mHoleRadius + strokeWidth/2;
            canvas.drawCircle(mCenterX,mCenterY,radius,mPaintBackground);

        }else {
            canvas.drawColor(mSplashBgColor);
        }
    }

    /**
     * 绘制圆
     * @param canvas
     */
    private void drawCircles(Canvas canvas) {
        //每个小圆得角度     2π/小圆的个数
        double rotationAngle = 2 * Math.PI / mCircleColors.length;

        for (int i = 0; i < mCircleColors.length; i++) {
            /**
             * x = r*cos(a) +centerX
             * y=  r*sin(a) + centerY
             * 每个小圆i*间隔角度 + 旋转的角度 = 当前小圆的真是角度
             */
            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);
        }

    }


    public void splashDisappear(){
        //开启后面两个动画
        //换模板--换状态
        if(mState!=null && mState instanceof RotateState){
            //结束旋转动画
            RotateState rotateState = (RotateState) mState;
            rotateState.cancel();
            post(new Runnable() {
                @Override
                public void run() {
                    mState = new MergingState();
                }
            });
        }
    }

    //策略模式
    private  abstract  class  SplashState{
        public abstract  void drawState(Canvas canvas);
        public void cancel(){
            mAnimator.cancel();
        }
    }
}

mCircleColors颜色参数

    <color name="splash_bg">#F8F6EC</color>
    <color name="orange">#FF9600</color>
    <color name="aqua">#02D1AC</color>
    <color name="yellow">#FFD200</color>
    <color name="blue">#00C6FF</color>
    <color name="green">#00E099</color>
    <color name="pink">#FF3892</color>

    <array name="splash_circle_colors">
        <item>@color/blue</item>
        <item>@color/green</item>
        <item>@color/pink</item>
        <item>@color/orange</item>
        <item>@color/aqua</item>
        <item>@color/yellow</item>
    </array>

mainactivity代码

public class MainActivity extends AppCompatActivity {


    private MySplashView splashView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        splashView = findViewById(R.id.splashview);
        startLoadData();
    }

    Handler handler = new Handler();
    private void startLoadData() {
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                //数据加载完毕,进入主界面--->开启后面的两个动画
                splashView.splashDisappear();
            }
        },5000);//延迟时间
    }
}

 R.layout.activity_main布局

<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@mipmap/test"
    tools:context=".MainActivity">

   <com.zkq.myanim.MySplashView
       android:id="@+id/splashview"
       android:layout_width="match_parent"
       android:layout_height="match_parent"/>

</androidx.constraintlayout.widget.ConstraintLayout>

完整demo下载地址: demo下载地址

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章