1. 程式人生 > >自定義控制元件之仿雅虎新聞載入

自定義控制元件之仿雅虎新聞載入

分析:
 1.先畫固定不動的圓,圍成一個大圓,均勻分佈在外圓上
 2.開始旋轉屬性動畫,獲取旋轉的角度3.開始內聚動畫,就是位移動畫,向大圓圓心移動
 4.水波紋效果,就是strokeWidth型別的圓向外移動,半徑不斷變大

                                                                     

public class SplashLoadingView extends View {
    private SplashState mSplashState;
    private float mRotationRadius;
    // 是否初始化引數
    private boolean mIsInitParams = false;
    // 繪製圓的畫筆
    private Paint mPaint = new Paint();
    // 繪製背景的畫筆
    private Paint mPaintBackground = new Paint();
    // 當前大圓旋轉的角度(弧度)
    private float mCurrentRotationAngle = 0F;
    private final long ROTATION_ANIMATION_TIME = 2000;
    // 第二部分動畫執行的總時間 (包括三個動畫的時間)
    private final long SPLASH_ANIMATION_TIME = 1200;
    private float mCircleRadius;
    private int mCenterX;
    private int mCenterY;
    private int[] mCircleColors;
    // 整體的顏色背景
    private int mSplashColor = Color.WHITE;
    private float mCurrentRotationRadius;
    // 空心圓初始半徑
    private float mHoleRadius = 0F;
    //螢幕對角線的一半
    private float mScreenDis;


    public SplashLoadingView(Context context) {
        this(context, null);
    }

    public SplashLoadingView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

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

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (!mIsInitParams) {
            initPatams();

        }
        if (mSplashState == null) {
            mSplashState = new RotationState();

        }
        mSplashState.draw(canvas);
    }

    private void initPatams() {
        int width = getMeasuredWidth();
        //大圓的半徑
        mRotationRadius = width / 4;
        mCircleRadius = mRotationRadius / 8;
        //螢幕中心位置
        mCenterX = width / 2;
        mCenterY = getMeasuredHeight() / 2;
        mScreenDis = (float) Math.sqrt(mCenterX * mCenterX + mCenterY * mCenterY);
        //小圓顏色列表
        mCircleColors = getContext().getResources().getIntArray(R.array.splash_circle_colors);
        //初始化畫筆
        mPaint.setDither(true);
        mPaint.setAntiAlias(true);
        mPaintBackground.setDither(true);
        mPaintBackground.setAntiAlias(true);
        mPaintBackground.setColor(mSplashColor);


    }

    public void disappear() {
        if (mSplashState instanceof RotationState) {
            RotationState splashState = (RotationState) mSplashState;
            splashState.cancelAnimator();
            mSplashState = new MergeState();
        }

    }

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

    /**
     * 繪製小圓旋轉動畫
     */
    private class RotationState extends SplashState {

        private ValueAnimator mValueAnimator;

        public RotationState() {
            //旋轉屬性動畫
            mValueAnimator = ValueAnimator.ofFloat(0, (float) (Math.PI * 2));
            mValueAnimator.setDuration(ROTATION_ANIMATION_TIME);
            mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    mCurrentRotationAngle = (float) animation.getAnimatedValue();
                    invalidate();
                }
            });
            mValueAnimator.setRepeatCount(-1);
            mValueAnimator.setInterpolator(new LinearInterpolator());
            mValueAnimator.start();

        }

        @Override
        public void draw(Canvas canvas) {
            //畫整個背景
            canvas.drawColor(mSplashColor);
            //繪製六個圓
            float preAngle = (float) (2 * Math.PI / mCircleColors.length);
            for (int i = 0; i < mCircleColors.length; i++) {
                mPaint.setColor(mCircleColors[i]);
                //初始角度+旋轉角度
                double angle = i * preAngle + mCurrentRotationAngle;
                float cx = (float) (mCenterX + mRotationRadius * Math.cos(angle));
                float cy = (float) (mCenterY + mRotationRadius * Math.sin(angle));
                canvas.drawCircle(cx, cy, mCircleRadius, mPaint);


            }

        }

        public void cancelAnimator() {

            mValueAnimator.cancel();
            mValueAnimator = null;
        }
    }

    /**
     * 小圓的聚合動畫
     */
    private class MergeState extends SplashState {

        private ValueAnimator mValueAnimator;

        public MergeState() {
            mValueAnimator = ValueAnimator.ofFloat(mRotationRadius, 0);
            mValueAnimator.setDuration(SPLASH_ANIMATION_TIME / 2);
            mValueAnimator.setInterpolator(new AnticipateInterpolator(6f));
            mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    mCurrentRotationRadius = (float) animation.getAnimatedValue();
                    invalidate();

                }
            });
            mValueAnimator.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    mSplashState = new ExpandingState();

                }
            });
            mValueAnimator.start();
        }

        @Override
        public void draw(Canvas canvas) {
            //畫整個背景
            canvas.drawColor(mSplashColor);
            //繪製六個圓
            float preAngle = (float) (2 * Math.PI / mCircleColors.length);
            for (int i = 0; i < mCircleColors.length; i++) {
                mPaint.setColor(mCircleColors[i]);
                //初始角度+旋轉角度
                double angle = i * preAngle + mCurrentRotationAngle;
                float cx = (float) (mCenterX + mCurrentRotationRadius * Math.cos(angle));
                float cy = (float) (mCenterY + mCurrentRotationRadius * Math.sin(angle));
                canvas.drawCircle(cx, cy, mCircleRadius, mPaint);


            }

        }
    }

    /**
     * 圓的擴散動畫
     */
    private class ExpandingState extends SplashState {

        private ValueAnimator mValueAnimator;

        public ExpandingState() {
            mValueAnimator = ObjectAnimator.ofFloat(0, mScreenDis);
            mValueAnimator.setDuration(ROTATION_ANIMATION_TIME / 2);
            mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    mHoleRadius = (float) animation.getAnimatedValue();
                    invalidate();
                }
            });
            mValueAnimator.start();
        }

        @Override
        public void draw(Canvas canvas) {
            float strokeWidth = mScreenDis - mHoleRadius;
            mPaint.setStrokeWidth(strokeWidth);
            mPaint.setColor(mSplashColor);
            mPaint.setStyle(Paint.Style.STROKE);
            float radius =strokeWidth/2+mHoleRadius;
            canvas.drawCircle(mCenterX,mCenterY,radius,mPaint);

        }
    }
}

 activity_main佈局如下

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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">

    <include layout="@layout/fragment_page_first"/>
    <com.example.ex_chenmengjia001.myview.view.SplashLoadingView
        android:id="@+id/thirdScreenView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:layout_editor_absoluteY="8dp"
        tools:layout_editor_absoluteX="8dp" />

</RelativeLayout>

 fragment_page_first佈局如下:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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">

    <include layout="@layout/fragment_page_first"/>
    <com.example.ex_chenmengjia001.myview.view.SplashLoadingView
        android:id="@+id/thirdScreenView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:layout_editor_absoluteY="8dp"
        tools:layout_editor_absoluteX="8dp" />

</RelativeLayout>
public class SplashActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_splash);
        final SplashLoadingView splashView = (SplashLoadingView) findViewById(R.id.thirdScreenView);

        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                splashView.disappear();
            }
        },2000);
    }
}