自定义点击产生涟漪效果
下面是效果图
1、本文以TextView为例,自定义一个RippleTextView和RippleDarwable。在RippleTextView构造方法中进行重绘
public RippleTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mRippleDrawable = new RippleDrawable(context);
mRippleDrawable.setCallback(this); //设置刷新接口,view中已经实现
mRippleDrawable.setRippleColor(Color.GRAY); //设置涟漪的颜色
}
mRippleDrawable.setBounds(0, 0, getWidth(), getHeight());
重写verifyDrawable方法,用来验证
protected boolean verifyDrawable(Drawable who) {
return who == mRippleDrawable || super.verifyDrawable(who);//验证drawable
}
重写onDraw方法,重写onTouchEvent方法,必须返回true不然后续动作执行会出问题。
public boolean onTouchEvent(MotionEvent event) { mRippleDrawable.onTouch(event); super.onTouchEvent(event); return true; }
自定义RippleTextView就完成了。
2、现在开始自定义RippleDarwable
2.1在构造方法中创建Paint,设置一系列参数优化画面
mPaint.setAntiAlias(true); //抗锯齿 mPaint.setDither(true); //防止颜色过度抖动 mPaint.setStyle(Paint.Style.FILL); //设置画笔为填充方式
2.2设置画笔的颜色,透明度。不过这些也可以不用写,毕竟用户设置基本上不上
public void setRippleColor(int color) { mRippleColor = color; onColorOrAlphaChange(); } @Override public void setAlpha(int i) { mAlpha = i; onColorOrAlphaChange(); } private void onColorOrAlphaChange() { mPaint.setColor(mRippleColor); //先设置画笔颜色(包含透明度) if (mAlpha != 255) { int pAlpha = Color.alpha(mRippleColor); mPaint.setAlpha((int) (pAlpha * (mAlpha / 255f))); //根据drawable的透明度设置画笔颜色的透明度 } }
2.3重写onBoundsChange方法,获取控件的中心点坐标以及做大半径
protected void onBoundsChange(Rect bounds) { super.onBoundsChange(bounds); mCenterPointX = bounds.centerX(); mCenterPointY = bounds.centerY(); float maxRadius = Math.max(mCenterPointX, mCenterPointY); mStartRadius = 0; mEndRadius = maxRadius * 0.8f; }
2.4重写onDarw方法
public void draw(Canvas canvas) { int preAlpha = mPaint.getAlpha(); int bgAlpha = (int) (preAlpha*(mBgAlpha/255f)); int maxCircleAlpha = getCircleAlpha(preAlpha,bgAlpha); int circleAlpha = (int) (maxCircleAlpha*(mCircleAlpha/255f)); mPaint.setAlpha(bgAlpha); canvas.drawColor(mPaint.getColor()); //绘制背景颜色 mPaint.setAlpha(circleAlpha); //设置画笔的透明度 canvas.drawCircle(mRipplePointX, mRipplePointY, mRippleRadius, mPaint); //画一个圆 mPaint.setAlpha(preAlpha); }
2.5控件的监听public void onTouch(MotionEvent event) { switch (event.getActionMasked()) { case MotionEvent.ACTION_DOWN: onTouchRelease = false; mDonePointX = event.getX(); mDonePointY = event.getY(); startEnterRunnable(); break; case MotionEvent.ACTION_MOVE: break; case MotionEvent.ACTION_UP: Log.e(TAG, "onTouch: ACTION_UP"); onTouchRelease = true; if (mEnterDone) startExitRunnable(); break; } }
2.6动画的逻辑
//启动进入动画 private void startEnterRunnable() { mCircleAlpha = 255; mEnterDone = false; mProgress = 0; unscheduleSelf(mEnterRunnable); unscheduleSelf(mExitRunnable); scheduleSelf(mEnterRunnable, SystemClock.uptimeMillis()); } private Runnable mEnterRunnable = new Runnable() { @Override public void run() { mProgress = mProgress + mEnterIncrement; if (mProgress > 1) { onEnterDone(); onEnterProgress(1); return; } float interpolation = mEnterInterpolator.getInterpolation(mProgress); onEnterProgress(interpolation); scheduleSelf(mEnterRunnable, SystemClock.uptimeMillis() + 16); } }; private void onEnterDone() { mEnterDone = true; if (onTouchRelease) startExitRunnable(); } private void onEnterProgress(float progress) { mRippleRadius = getProgressValue(mStartRadius, mEndRadius, progress); mRipplePointX = getProgressValue(mDonePointX, mCenterPointX, progress); mRipplePointY = getProgressValue(mDonePointY, mCenterPointY, progress); mBgAlpha = (int) getProgressValue(0, MAX_BG_ALPHA, progress); invalidateSelf(); //刷新界面 } //启动退出动画 private void startExitRunnable() { mExitProgress = 0; unscheduleSelf(mEnterRunnable); unscheduleSelf(mExitRunnable); scheduleSelf(mExitRunnable, SystemClock.uptimeMillis()); } private Runnable mExitRunnable = new Runnable() { @Override public void run() { if (!mEnterDone)return; //判断进入动画是否进行中 mExitProgress = mExitProgress + mExitIncrement; if (mExitProgress > 1) { onExitProgress(1); //当mExitProgress > 1时,onExitProgress方法没有执行,所以在此处进行调用 return; } float interpolation = mExitInterpolator.getInterpolation(mExitProgress); onExitProgress(interpolation); scheduleSelf(mExitRunnable, SystemClock.uptimeMillis() + 16); } }; private void onExitProgress(float progress) { mBgAlpha = (int) getProgressValue(MAX_BG_ALPHA, 0, progress); mCircleAlpha = (int) getProgressValue(MAX_CIRCLE_ALPHA,0,progress); //设置圆形的透明度,以达到变淡到消失过程 invalidateSelf(); //刷新界面 } private float getProgressValue(float start, float end, float progress) { return start + (end - start) * progress; }
在draw方法中反向获取透明度,我们在知道两个透明度的时候反向推出第三个透明度。中学经常有这样的数学题目
/** * 反向获取透明度算法 * @param preAlpha * @param bgAlpha * @return */ private int getCircleAlpha(int preAlpha,int bgAlpha) { int dAlpha = preAlpha - bgAlpha; return (int) (dAlpha*255f/(255f-bgAlpha)); }
大体上就是这样的,有兴趣试试吧。