1. 程式人生 > >RippleView水波紋,漣漪效果

RippleView水波紋,漣漪效果

模仿水波紋,漣漪效果,可用於裝置查詢之類的特效

其實這是一個很簡單的自定義View,只需要一個類,然後對外提供狀態回撥介面和設定屬性的方法即可。

下面要說設計思路了。

1,自定義一個View。

2,在onDraw方法裡畫圓,初始化畫筆,半徑多少,要畫幾個圓,實心圓還是空心圓,這些都要想好。

3,通過ValueAnimator 動畫每一貞的回撥改變圓半徑,呼叫postInvalidate方法不斷重繪,就能產生水波紋效果了。

4,設定狀態監聽器,設定注入方法,在該使用的地方回撥一把出去。

5,設定圓的屬性引數的方法。

6,在外面使用。

水波紋自定義View,設計思路就是醬子。

接下來看程式碼詳細的分析上述所說的步驟。

1,自定義一個View。


    public class RippleView extends View {

        public RippleView(Context context) {
            super(context);
            init();
        }

        public RippleView(Context context, AttributeSet attrs) {
            super(context, attrs);
            init();
        }

        public
RippleView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } }

2,在onDraw方法裡畫圓,初始化畫筆,半徑多少,要畫幾個圓,實心圓還是空心圓,這些都要想好。

初始化畫筆,半徑。注意mChangeRadius為動畫開始後不斷改變的半徑值,為了不斷畫更大的圓。


        private void init() {
            mRadius = dip2px(NORMAL_RADIUS);
            mChangeRadius = mRadius;

            //初始化實心內圓畫筆
mInPaint.setColor(getResources().getColor(R.color.white10)); mInPaint.setAntiAlias(true); mInPaint.setStyle(Paint.Style.FILL); //初始化空心內圓畫筆 mInStrokePaint.setColor(getResources().getColor(R.color.white50)); mInStrokePaint.setAntiAlias(true); mInStrokePaint.setStyle(Paint.Style.STROKE); mInStrokePaint.setStrokeWidth(dip2px(mStrokeWidth)); //初始化空心外圓畫筆 mOutStrokePaint.setColor(getResources().getColor(R.color.white50)); mOutStrokePaint.setAntiAlias(true); mOutStrokePaint.setStyle(Paint.Style.STROKE); mOutStrokePaint.setStrokeWidth(dip2px(mStrokeWidth)); }

初始化圓心


        @Override
        protected void onSizeChanged(int w, int h, int oldw, int oldh) {
            super.onSizeChanged(w, h, oldw, oldh);
            //初始化圓心
            mCx = getMeasuredWidth() / 2;
            mCy = getMeasuredHeight() / 2;
        }

畫圓。這裡水波紋的圓畫了三個。開始先畫一個,等第一個半徑變為初始值1.5倍時畫第二個圓,2倍畫第三個圓。注意圓半徑的值計算。


        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            //畫半徑變化的外圓
            canvas.drawCircle(mCx, mCy, mChangeRadius, mOutStrokePaint);

            if(mChangeRadius >= mRadius * 1.5) {
                canvas.drawCircle(mCx, mCy, mChangeRadius - (mRadius / 2) , mOutStrokePaint);
            }

            if(mChangeRadius >= mRadius * 2) {
                canvas.drawCircle(mCx, mCy, mChangeRadius - (mRadius), mOutStrokePaint);
            }

            //畫實心內圓
            canvas.drawCircle(mCx, mCy, mRadius, mInPaint);
            //畫空心內圓
            canvas.drawCircle(mCx, mCy, mRadius, mInStrokePaint);
        }

3,通過ValueAnimator 動畫每一貞的回撥改變圓半徑,呼叫postInvalidate方法不斷重繪,就能產生水波紋效果了。

動畫值的變化區域這裡設定為:


    mValueAnimator.setIntValues(mRadius, (int) (mCx > mCy ? mCx * 1.4 : mCy * 1.4));

設定開啟水波紋動畫和關閉水波紋動畫的方法。


        /** 開啟水波紋 */
        public void startRipple() {
            if (mValueAnimator == null) {
                mValueAnimator = new ValueAnimator();
                mValueAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
                mValueAnimator.setIntValues(mRadius, (int) (mCx > mCy ? mCx * 1.4 : mCy * 1.4));
                mValueAnimator.setDuration(mDuration);
                mValueAnimator.setRepeatCount(mRepeatCount);
                mValueAnimator.addUpdateListener(this);
                mValueAnimator.addListener(this);
                mValueAnimator.start();
            } else {
                if (!mValueAnimator.isRunning()) {
                    mValueAnimator.start();
                }
            }
        }

        /** 關閉水波紋 */
        public void stopRipple() {
            if (mValueAnimator != null) {
                mValueAnimator.end();
            }
        }

處理每一貞動畫的邏輯。計算出最新的半徑值給圓,然後不斷重繪。


        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            mChangeRadius = (int) animation.getAnimatedValue();
            postInvalidate();
            if (mRippleStateListener != null) {
                mRippleStateListener.onRippleUpdate(animation);
            }
        }

設定狀態監聽器,設定注入方法,在該使用的地方回撥一把出去。


        /** 對外提供狀態資訊的介面 */
        public interface RippleStateListener {

            /** 動畫開始 */
            void startRipple();

            /** 動畫結束 */
            void stopRipple();

            /** 每一貞動畫回撥 */
            void onRippleUpdate(ValueAnimator animation);
        }

        /** 水波紋狀態介面物件注入 */
        public void setRippleStateListener(RippleStateListener listener) {
            mRippleStateListener = listener;
        }



        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            mChangeRadius = (int) animation.getAnimatedValue();
            postInvalidate();
            if (mRippleStateListener != null) {
                mRippleStateListener.onRippleUpdate(animation);
            }
        }

        @Override
        public void onAnimationStart(Animator animation) {
            if (mRippleStateListener != null) {
                mRippleStateListener.startRipple();
            }
        }

        @Override
        public void onAnimationEnd(Animator animation) {
            if (mRippleStateListener != null) {
                mRippleStateListener.stopRipple();
            }
            //動畫結束,初始變化的半徑
            mChangeRadius = mRadius;
        }

5,設定圓的屬性引數的方法。


        /** 設定圓半徑 */
        public void setRadius(int radius) {
            mRadius = radius;
            mChangeRadius = radius;
        }

        /** 設定圓邊線寬度 */
        public void setStrokeWidth(int strokeWidth) {
            mStrokeWidth = strokeWidth;
        }

        /** 設定動畫時間 */
        public void setDuration(int duration) {
            mDuration = duration;
        }

        /** 設定動畫次數 */
        public void setRepeatCount(int repeatCount) {
            mRepeatCount = repeatCount;
        }

        /** 設定圓心 */
        public void setCirclePoint(float x ,float y) {
            mCx = x;
            mCy = y;
        }

        /** 設定空心外圓顏色 */
        public void setOutStrokePaintColor(int color) {
            mOutStrokePaint.setColor(color);
        }

        /** 設定空心內圓顏色 */
        public void setInStrokePaintColor(int color) {
            mInStrokePaint.setColor(color);
        }

        /** 設定實心內圓顏色 */
        public void setInPaintColor(int color) {
            mInPaint.setColor(color);
        }

6,在外面使用。


            mRippleView = (RippleView) findViewById(R.id.root_rv);
            mRippleView.setRippleStateListener(this);

            public void start(View v) {
                mRippleView.startRipple();
            }

            public void stop(View v) {
                mRippleView.stopRipple();
            }

            @Override
            public void startRipple() {
                mTextView.setText("0%");
            }

            @Override
            public void stopRipple() {

            }

            @Override
            public void onRippleUpdate(ValueAnimator animation) {
                float fraction = animation.getAnimatedFraction();
                int value = (int) (fraction * 100);
                mTextView.setText(String.valueOf(value) + "%");
            }

漣漪,水波紋自定義就這樣分析完了。

再來看一次效果圖:

就到這裡了,小程式一枚。

2016年7月02日 18:00:21