Android 点击波纹扩散动画

2,213 阅读2分钟

前言

 国际惯例先放图

gif动画将就看吧,要啥自行车,真机上效果还可以。

大体思路

通过继承Drawable重写draw()方法,通过ValueAnimator不断改变圆的半径,实现波纹效果。注意的一点是波纹要从手机点击抬起的位置为中心向俩边扩散。看下代码:

public class WaveDrawable extends Drawable {
    private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    private int mViewWidth;
    private int mViewHeight;
    private ValueAnimator mValueAnimator;
    private int mRadius;

    private int mEndColor;
    private int mStartColor;
    private float mClickX;
    private float mClickY;

    public WaveDrawable(@ColorInt int originColor, @ColorInt int targetColor, int clickX, int clickY) {
        mStartColor = originColor;
        mEndColor = targetColor;
        mClickX = clickX;
        mClickY = clickY;
    }


    public void setClickXY(float clickX, float clickY) {
        mClickX = clickX;
        mClickY = clickY;
    }
    public void setColors(int startColor, int endColor) {
        mStartColor = startColor;
        mEndColor = endColor;
    }


    @Override
    public void draw(@NonNull Canvas canvas) {
        canvas.drawColor(mStartColor);
        mPaint.setColor(mEndColor);
        canvas.drawCircle(mClickX, mClickY, mRadius, mPaint);
    }

    @Override
    public void setAlpha(int alpha) {

    }

    @Override
    public void setColorFilter(@Nullable ColorFilter colorFilter) {

    }

    @Override
    public int getOpacity() {
        return PixelFormat.UNKNOWN;
    }

    @Override
    protected void onBoundsChange(Rect bounds) {
        mViewWidth = Math.abs(bounds.width());
        mViewHeight = Math.abs(bounds.height());
        int maxRadius = (int) Math.sqrt((mViewWidth * mViewWidth + mViewHeight * mViewHeight));

        mValueAnimator = ValueAnimator.ofInt(0, maxRadius);
        mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                //改变波纹半径
                mRadius = (int) animation.getAnimatedValue();
                invalidateSelf();
            }
        });
        mValueAnimator.setDuration(500);
    }

    /**
     * 波纹扩散动画开始
     */
    public void start() {
        if (mValueAnimator != null) {
            mValueAnimator.start();
        }
    }


}

在 onBoundsChange()中,计算了最大半径,并初始化了mValueAnimator ,实现半径的不断变化,通过invalidateSelf(),不断调用draw()绘制半径不断增大的圆,形成波纹扩散效果。

那么问题来了,怎么获取当前手指点击的位置呢?其实很简单只要在对应的View中重写dispatchTouchEvent(),那么event.getAction() == MotionEvent.ACTION_UP的时候,获取当前事件的坐标就行了看下代码:

public class WaveTextView extends android.support.v7.widget.AppCompatTextView {
    private int mStartColor = Color.parseColor("#FF5555");
    private int mEndColor = Color.parseColor("#23C865");
    private WaveDrawable mWaveDrawable = new WaveDrawable(mStartColor, mEndColor, 0, 0);
    private boolean mIsSwitch;

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

    public WaveTextView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public WaveTextView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        setClickable(true);
        setBackground(mWaveDrawable);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_UP) {
            //为了测试方便看效果加的
            if (mIsSwitch) {
                mWaveDrawable.setColors(mEndColor, mStartColor);
            } else {
                mWaveDrawable.setColors(mStartColor, mEndColor);
            }
            mWaveDrawable.setClickXY(event.getX(), event.getY());
            mWaveDrawable.start();
            mIsSwitch = !mIsSwitch;

        }
        return super.dispatchTouchEvent(event);
    }

}

注意 setClickable(true)最好设置下,要不然对于TextView这种View的话如果没有setOnClickListener()是默认收不到MotionEvent.ACTION_UP事件。

后记

这种效果实现起来很简单,但是细节还不少像setClickable(true)的问题在源码里面找了好一会才定位到问题,代码github,觉得对你有帮助的话,顺手给个星吧!