先来看看效果图吧
新建一个android应用之后,修改activity.xml文件
包名改为自己的包名就行了
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/activity_main"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp"
tools:context=".MainActivity">
<com.huiyi.touchripple.widget.RippleButton
android:layout_width="match_parent"
android:layout_height="100dp"
android:background="@mipmap/img"
android:layout_centerInParent="true"
android:text="@string/ripplebutton"
android:textColor="@color/colorAccent"
android:gravity="center" />
</RelativeLayout>
新建一个widget的包,新建一个RippleDrawable的类
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.SystemClock;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.Log;
import android.view.MotionEvent;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
public class RippleDrawable extends Drawable {
// 最大的透明度
public static final int MAX_ALPHA_BG = 172;
public static final int MAX_ALPHA_CIRCLE = 255;
// 0~255透明度
private int mAlpha = 200;
private int mRippleColor = 0;
// 画笔
private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
// 圆心坐标
private float mRipplePointX,mRipplePointY;
// 半径
private float mRippleRadius = 0;
// 背景透明度,圆形透明度
private int mBgAlpha = 0,mCircleAlpha = MAX_ALPHA_CIRCLE;
// 标识用户手是否抬起
private boolean mTouchRelease;
// 按下时的点击点
private float mDonePointX,mDonePointY;
// 控件的中心区域点
private float mCenterPointX,mCenterPointY;
// 开始和结束的半径
private float mStartRadius,mEndRadius;
public RippleDrawable(int color){
// 抗锯齿
mPaint.setAntiAlias(true);
// 防抖动
mPaint.setDither(true);
// 设置画笔为填充方式
mPaint.setStyle(Paint.Style.FILL);
// 设置涟漪颜色
setRippleColor(color);
// ARGB 0xff ff ff ff
// 设置滤镜
// setColorFilter(new LightingColorFilter(0xffff0000,0x00330000));
}
public void onTouch(MotionEvent event){
// 判断点击操作类型
switch (event.getActionMasked()){
case MotionEvent.ACTION_DOWN:
onTouchDown(event.getX(),event.getY());
break;
case MotionEvent.ACTION_MOVE:
onTouchMove(event.getX(),event.getY());
break;
case MotionEvent.ACTION_UP:
onTouchUp(event.getX(),event.getY());
break;
case MotionEvent.ACTION_CANCEL:
onTouchCancel(event.getX(),event.getY());
break;
}
}
private void onTouchDown(float x,float y){
mDonePointX = x;
mDonePointY = y;
// 按下,没有抬起
mTouchRelease = false;
startEnterRunnable();
}
private void onTouchMove(float x,float y){
}
private void onTouchUp(float x,float y){
// 标识手抬起
mTouchRelease = true;
// 当进入动画完成时,启动退出动画
if (mEnterDone){
startExitRunnable();
}
// unscheduleSelf(mEnterRunnable);
}
private void onTouchCancel(float x,float y){
// 标识手抬起
mTouchRelease = true;
// 当进入动画完成时,启动退出动画
if (mEnterDone){
startExitRunnable();
}
}
/**
* 设置涟漪的颜色
* @param color color
*/
public void setRippleColor(int color){
// 不建议直接设置
// mPaint.setColor(color);
mRippleColor = color;
onColorAlphaChange();
}
/**
* 启动进入动画
*/
private void startEnterRunnable(){
mCircleAlpha = MAX_ALPHA_CIRCLE;
mEnterProgress = 0;
mEnterDone = false;
// 取消事物的操作
unscheduleSelf(mExitRunnable);
unscheduleSelf(mEnterRunnable);
// 注入一个进入动画
scheduleSelf(mEnterRunnable,SystemClock.uptimeMillis());
}
/**
* 启动退出动画
*/
private void startExitRunnable(){
mExitProgress = 0;
// 取消事物的操作
unscheduleSelf(mEnterRunnable);
unscheduleSelf(mExitRunnable);
// 注入一个退出动画
scheduleSelf(mExitRunnable,SystemClock.uptimeMillis());
}
// 标识进入动画是否完成
private boolean mEnterDone;
// 进入动画进度值
private float mEnterProgress = 0;
// 每次递增的进度值
private float mEnterIncreement = 16f/360;
// 进入动画插值器,用于实现从快到慢的效果
private Interpolator mEnterInterpolator = new DecelerateInterpolator(2);
// 动画的回调
private Runnable mEnterRunnable = new Runnable() {
@Override
public void run() {
mEnterProgress = mEnterProgress + mEnterIncreement;
if (mEnterProgress > 1){
onEnterProgress(1);
onEnterDone();
return;
}
float realProgress = mEnterInterpolator.getInterpolation(mEnterProgress);
onEnterProgress(realProgress);
// 延迟16毫秒,保证界面刷新频率接近60fps
scheduleSelf(this,SystemClock.uptimeMillis() + 16);
}
};
/**
* 当进入动画完成时触发
*/
private void onEnterDone(){
Log.e("TAG","onEnterDone");
mEnterDone = true;
// 当用户手放开时,启动退出动画
if (mTouchRelease){
startExitRunnable();
}
}
/**
* 进入动画刷新方法
* @param progress 进度值
*/
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_ALPHA_BG,progress);
invalidateSelf();
}
// 退出动画进度值
private float mExitProgress = 0;
// 每次递增的进度值
private float mExitIncreement = 16f/300;
// 退出动画插值器,用于实现从慢到快的效果
private Interpolator mExitInterpolator = new AccelerateInterpolator(2);
// 动画的回调
private Runnable mExitRunnable = new Runnable() {
@Override
public void run() {
// 进入时,首选判断进入动画是否具有
if (!mEnterDone){
return;
}
mExitProgress = mExitProgress + mExitIncreement;
if (mExitProgress > 1){
onExitProgress(1);
onExitDone();
return;
}
float realProgress = mExitInterpolator.getInterpolation(mExitProgress);
onExitProgress(realProgress);
// 延迟16毫秒,保证界面刷新频率接近60fps
scheduleSelf(this,SystemClock.uptimeMillis() + 16);
}
};
/**
* 当退出动画完成时触发
*/
private void onExitDone(){
Log.e("TAG","onExitDone");
}
/**
* 退出动画刷新方法
* @param progress 进度值
*/
private void onExitProgress(float progress){
Log.e("TAG","onExitProgress:" + progress);
// 背景减淡
mBgAlpha = (int) getProgressValue(MAX_ALPHA_BG,0,progress);
// 圆形减淡
mCircleAlpha = (int) getProgressValue(MAX_ALPHA_CIRCLE,0,progress);
invalidateSelf();
}
private float getProgressValue(float start,float end,float progress){
return start + (end - start) * progress;
}
/**
* 界面大小改变时触发,我们在这里运算中心点,以及半径
* @param bounds Rect
*/
@Override
protected void onBoundsChange(Rect bounds) {
super.onBoundsChange(bounds);
mCenterPointX = bounds.centerX();
mCenterPointY = bounds.centerY();
// 得到圆的最大半径
float maxRadius = Math.max(mCenterPointX,mCenterPointY);
mStartRadius = maxRadius * 0f;
mEndRadius = maxRadius * 0.8f;
}
/*// 更改颜色透明度方法
private int changeColorAlpha(int color,int alpha){
int a = (color >> 24) & 0xFF;
a = (int) (a * (alpha/255f));
int r = (color >> 16) & 0xFF;
int g = (color >> 8) & 0xFF;
int b = (color) & 0xFF;
return (alpha << 24) | (r << 16) | (g << 8) | b;
}*/
/**
* 通过两块玻璃叠加后颜色更深,
* 光线透过更少的算法反向推出其中一块玻璃块的值的算法
* @param preAlpha Z值,结合后的值
* @param bgAlpha Y值,其中一块玻璃块的值
* @return 返回另外一块玻璃块的值
*/
private int getCircleAlpha(int preAlpha,int bgAlpha){
int dAlpha = preAlpha - bgAlpha;
return (int) ((dAlpha * 255f) / (255f-bgAlpha));
}
@Override
public void draw(@NonNull 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);
}
@Override
public void setAlpha(int alpha) {
// 设置Drawable的透明度
mAlpha = alpha;
onColorAlphaChange();
}
@Override
public int getAlpha() {
return mAlpha;
}
private void onColorAlphaChange(){
// 0x30ffffff
mPaint.setColor(mRippleColor);
Log.e("TAG","set:" + mPaint.getColor());
if (mAlpha != 255){
// 得到颜色本身的透明度
// 0x30
int pAlpha = mPaint.getAlpha();
//pAlpha = Color.alpha(mRippleColor);
int realAlpha = (int) (pAlpha *(mAlpha / 255f));
mPaint.setAlpha(realAlpha);
Log.e("TAG","Old:" + mRippleColor + "new:" + mPaint.getColor());
}
// 刷新当前Drawable
invalidateSelf();
}
@Override
public void setColorFilter(@Nullable ColorFilter colorFilter) {
// 颜色滤镜
if (mPaint.getColorFilter() != colorFilter){
mPaint.setColorFilter(colorFilter);
// 刷新当前Drawable
invalidateSelf();
}
}
@Override
public int getOpacity() {
int alpha = mPaint.getAlpha();
if (alpha == 255){
// 不透明的drawable
return PixelFormat.OPAQUE;
} else if (alpha == 0){
// 全透明的drawable
return PixelFormat.TRANSPARENT;
} else {
// 半透明的drawable
return PixelFormat.TRANSLUCENT;
}
}
}
新建一个RippleButton的类
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.support.annotation.NonNull;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.Button;
@SuppressLint("AppCompatCustomView")
public class RippleButton extends Button {
private RippleDrawable mRippleDrawable;
public RippleButton(Context context) {
this(context,null);
}
public RippleButton(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public RippleButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mRippleDrawable = new RippleDrawable(0x60000000);
// 设置刷新接口,View中已经实现
mRippleDrawable.setCallback(this);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
// 设置Drawable绘制和刷新的区域
mRippleDrawable.setBounds(0,0,getWidth(),getHeight());
}
@Override
protected boolean verifyDrawable(@NonNull Drawable who) {
// 验证Drawable是否ok
return who == mRippleDrawable || super.verifyDrawable(who);
}
@Override
protected void onDraw(Canvas canvas) {
// 绘制自己的Drawable
mRippleDrawable.draw(canvas);
super.onDraw(canvas);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
mRippleDrawable.onTouch(event);
super.onTouchEvent(event);
return true;
}
}