Android Ripple 按钮水波纹效果(一)

看到android 5.0有一个按钮点击效果非常棒,先来看效果图:
Android Ripple 按钮水波纹效果(一)_第1张图片

但是这种效果只能在5.0的系统上有效果,如何在低版本上实现呢?
这种效果网上也有人实现了,
blog 地址http://blog.csdn.net/singwhatiwanna/article/details/42614953

ok,直接进入主题,
要实现这种动画效果也不难,原理可以用一句话概括:就是,在我们按下view的时候,从按下的位置开始绘制圆,圆的半径一直增大,直至把View全部覆盖掉。

通过实现原理我们可以分析出,要实现这种效果,需要重写onDraw方法,onTouchEvent方法,如果有必要还需要通过onMeasure方法来获取View的size

1、onDraw方法,就是不断的绘制圆,这里需要循环调用,
2、onTouchEvent方法:通过MotionEvent.ACTION_DOWN和MotionEvent.ACTION_UP做相应的操作并触发onDraw方法
3、onMeasure计算View的size,通过size加上MotionEvent.ACTION_DOWN起始点计算出圆的最大半径

代码实现:
保存view的大小,用于计算绘制 圆的最大半径

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
   super.onMeasure(widthMeasureSpec, heightMeasureSpec);
   mRect.set(0, 0, getMeasuredWidth(), getMeasuredHeight());
}

手指按下view的时候,计算按下点的位置,并触发onDraw方法

public boolean onTouchEvent(MotionEvent event) {
        final int action = MotionEventCompat.getActionMasked(event);
        switch (action) {
            case MotionEvent.ACTION_DOWN: {
                mDrawFinish = false;
                int index = MotionEventCompat.getActionIndex(event);
                int eventId = MotionEventCompat.getPointerId(event, index);
                if (eventId != -1) {
                    mInitX = (int) MotionEventCompat.getX(event, index);
                    mInitY = (int) MotionEventCompat.getY(event, index);
                    updateDrawData();
                    ViewCompat.postInvalidateOnAnimation(this);
                }
                return true;
            }

更新数据,重新计算圆的半径和步长

private void updateDrawData() {
        int radiusLeftTop = (int) Math.sqrt((mRect.left - mInitX) * (mRect.left - mInitX) +
                (mRect.top - mInitY) * (mRect.top - mInitY));
        int radiusRightTop = (int) Math.sqrt((mRect.right - mInitX) * (mRect.right - mInitX) +
                (mRect.top - mInitY) * (mRect.top - mInitY));
        int radiusLeftBottom = (int) Math.sqrt((mRect.left - mInitX) * (mRect.left - mInitX) +
                (mRect.bottom - mInitY) * (mRect.bottom - mInitY));
        int radiusRightBottom = (int) Math.sqrt((mRect.right - mInitX) * (mRect.right - mInitX) +
                (mRect.bottom - mInitY) * (mRect.bottom - mInitY));
        mRadius = getMax(radiusLeftTop, radiusRightTop, radiusLeftBottom, radiusRightBottom);
        mStep = mRadius/mCycle;
    }

手指抬起的时候需要做的操做,把步长加大2.5倍,加快圆的绘制

 @Override
    public boolean onTouchEvent(MotionEvent event) {
        final int action = MotionEventCompat.getActionMasked(event);
        switch (action) {
        //..
            case MotionEvent.ACTION_CANCEL:
            case MotionEvent.ACTION_UP:
                mStep = (int) (2.5f * mStep);
                mDrawBack = true ;
                break;
        }
        return super.onTouchEvent(event);
    }

最后就是绘制圆了,这里需要做判断,如果当前绘制的圆半径没有达到我们计算的最大半径,需要继续绘制

@Override
    protected void onDraw(Canvas canvas) {
        if (mDrawFinish) {
            super.onDraw(canvas);
            return;
        }
        canvas.drawColor(0x08000000);
        super.onDraw(canvas);
        if (mStep == 0) {
            return;
        }
        mDrawRadius = mDrawRadius + mStep;


        if (mDrawRadius > mRadius) {
            mDrawRadius = 0;
            canvas.drawCircle(mInitX, mInitY, mRadius, mRevealPaint);
            mDrawFinish = true;
            ViewCompat.postInvalidateOnAnimation(this);
            return;
        }

        canvas.drawCircle(mInitX, mInitY, mDrawRadius, mRevealPaint);
        ViewCompat.postInvalidateOnAnimation(this);
    }

整个效果的实现,相对比较简单,只是很无聊的一直绘圆。
最后要说明一点,如果你想对TextView做这种效果,则继承TextView即可,LinearLayout等其他组件同理;

demo下载

你可能感兴趣的:(动画,自定义View)