前言
国际惯例先放图
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,觉得对你有帮助的话,顺手给个星吧!
码字不易,期待各位的赞赏!!!