import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import com.xtc.uvmeasure.util.DensityUtil;
import java.util.ArrayList;
import java.util.List;
public class RippleView extends View {
private Context mContext;
// 畫筆對象
private Paint mPaint;
// View寬
private float mWidth;
// View高
private float mHeight;
// 聲波的圓圈集合
private List<Circle> mRipples;
private int sqrtNumber;
// 圓圈擴散的速度
private int mSpeed;
// 圓圈之間的密度
private int mDensity;
// 圓圈的顏色
private int mColor;
// 圓圈是否爲填充模式
private boolean mIsFill;
// 圓圈是否爲漸變模式
private boolean mIsAlpha;
public RippleView(Context context) {
this(context, null);
}
public RippleView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public RippleView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
// 獲取用戶配置屬性
TypedArray tya = context.obtainStyledAttributes(attrs, R.styleable.mRippleView);
mColor = tya.getColor(R.styleable.mRippleView_cColor, Color.BLUE);
mSpeed = 2;
mDensity = tya.getInt(R.styleable.mRippleView_cDensity, 10);
mIsFill = tya.getBoolean(R.styleable.mRippleView_cIsFill, false);
mIsAlpha = tya.getBoolean(R.styleable.mRippleView_cIsAlpha, false);
tya.recycle();
init();
}
private void init() {
mContext = getContext();
// 設置畫筆樣式
mPaint = new Paint();
mPaint.setColor(mColor);
mPaint.setStrokeWidth(DensityUtil.dip2px(mContext, 1));
if (mIsFill) {
mPaint.setStyle(Paint.Style.FILL);
} else {
mPaint.setStyle(Paint.Style.STROKE);
}
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setAntiAlias(true);
// 添加第一個圓圈
mRipples = new ArrayList<>();
Circle c = new Circle(120, 255);
mRipples.add(c);
mDensity = DensityUtil.dip2px(mContext, mDensity);
// 設置View的圓爲半透明
setBackgroundColor(Color.TRANSPARENT);
}
private boolean isDrow ;
public boolean isDrow() {
return isDrow;
}
public void setDrow(boolean drow) {
isDrow = drow;
}
public List<Circle> getmRipples() {
return mRipples;
}
@Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
// 內切正方形
drawInCircle(canvas);
// 外切正方形
// drawOutCircle(canvas);
}
/**
* 圓到寬度
*
* @param canvas
*/
private void drawInCircle(Canvas canvas) {
if (isDrow()) {
canvas.save();
// 處理每個圓的寬度和透明度
for (int i = 0; i < mRipples.size(); i++) {
Circle c = mRipples.get(i);
mPaint.setAlpha(c.alpha);// (透明)0~255(不透明)
canvas.drawCircle(mWidth / 2, mHeight / 2, c.width - mPaint.getStrokeWidth(), mPaint);
// 當圓超出View的寬度後刪除
if (c.width > mWidth/2) {
mRipples.remove(i);
} else {
// 計算不透明的數值,這裏有個小知識,就是如果不加上double的話,255除以一個任意比它大的數都將是0
if (mIsAlpha) {
double alpha = 255 - c.width * (255 / ((double) mWidth / 2));
c.alpha = (int) alpha;
}
// 修改這個值控制速度
c.width += mSpeed;
}
}
// 裏面添加圓
if (mRipples.size() > 0) {
// 控制第二個圓出來的間距
if (mRipples.get(mRipples.size() - 1).width > DensityUtil.dip2px(mContext, mDensity)) {
mRipples.add(new Circle(0, 255));
}
}
invalidate();
canvas.restore();
}
}
/**
* 圓到對角線
*
* @param canvas
*/
private void drawOutCircle(Canvas canvas) {
canvas.save();
// 使用勾股定律求得一個外切正方形中心點離角的距離
sqrtNumber = (int) (Math.sqrt(mWidth * mWidth + mHeight * mHeight) / 2);
// 變大
for (int i = 0; i < mRipples.size(); i++) {
// 啓動圓圈
Circle c = mRipples.get(i);
mPaint.setAlpha(c.alpha);// (透明)0~255(不透明)
canvas.drawCircle(mWidth / 2, mHeight / 2, c.width - mPaint.getStrokeWidth(), mPaint);
// 當圓超出對角線後刪掉
if (c.width > sqrtNumber) {
mRipples.remove(i);
} else {
// 計算不透明的度數
double degree = 255 - c.width * (255 / (double) sqrtNumber);
c.alpha = (int) degree;
c.width += 1;
}
}
// 裏面添加圓
if (mRipples.size() > 0) {
// 控制第二個圓出來的間距
if (mRipples.get(mRipples.size() - 1).width == 50) {
mRipples.add(new Circle(0, 255));
}
}
invalidate();
canvas.restore();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int myWidthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
int myWidthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
int myHeightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
int myHeightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
// 獲取寬度
if (myWidthSpecMode == MeasureSpec.EXACTLY) {
// match_parent
mWidth = myWidthSpecSize;
} else {
// wrap_content
mWidth = DensityUtil.dip2px(mContext, 120);
}
// 獲取高度
if (myHeightSpecMode == MeasureSpec.EXACTLY) {
mHeight = myHeightSpecSize;
} else {
// wrap_content
mHeight = DensityUtil.dip2px(mContext, 120);
}
// 設置該view的寬高
setMeasuredDimension((int) mWidth, (int) mHeight);
}
class Circle {
Circle(int width, int alpha) {
this.width = width;
this.alpha = alpha;
}
int width;
int alpha;
}
}
自定義屬性
<!--漣漪控件屬性-->
<declare-styleable name="mRippleView">
<attr name="cColor" format="color"/>
<attr name="cSpeed" format="integer"/>
<attr name="cDensity" format="integer"/>
<attr name="cIsFill" format="boolean"/>
<attr name="cIsAlpha" format="boolean"/>
</declare-styleable>
佈局文件使用
<com.xxx.xxx.RippleView
android:id="@+id/rpv_ripple"
android:layout_width="155dp"
android:layout_height="155dp"
android:layout_centerInParent="true"
app:cColor="@color/q"
app:cDensity="8"
app:cIsAlpha="false" />
頁面調用
RippleView diffuseView = (RippleView) findViewById(R.id.rpv_ripple);
// 點擊則開始縮放 自己寫點擊事件吧...
boolean drow = diffuseView.isDrow();
if (drow) {
diffuseView.setDrow(false);
}else{
diffuseView.setDrow(true);
diffuseView.invalidate();
}
原文地址:https://blog.csdn.net/zhuwentao2150/article/details/79452735