RippleView水波纹,涟漪效果

模仿水波纹,涟漪效果,可用于设备查找之类的特效

RippleView水波纹,涟漪效果_第1张图片

Demo下载:我的Github 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) + "%");
            }

涟漪,水波纹自定义就这样分析完了。

再来看一次效果图:

RippleView水波纹,涟漪效果_第2张图片

就到这里了,小程序一枚。

Demo下载:我的Github RippleView

2016年7月02日 18:00:21

你可能感兴趣的:(Android)