自定义波纹WaveView


效果图

首先直接上效果图:
图片

源码和分析

简单分析,首先画一个半径固定为R的颜色填充的圆,再画一些半径从R逐渐增大的圆就形成圆形不断的向外扩大的效果,并且这些圆形的透明度是与半径的相关的。最后在圆形的中心画文本。

自定义属性

attrs.xml

1
2
3
4
5
6
<declare-styleable name="waveView">
<attr name="text" format="string"/>
<attr name="textSize" format="dimension"/>
<attr name="textColor" format="color"/>
<attr name="color" format="color"/>
</declare-styleable>

text是圆形中心的文本,textSize是文本的大小,textColor是文本的颜色,color是WaveView的颜色。

WaveView.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
public class WaveView extends View {
private int mRippleViewWidth;
private int mRippleViewRadius;
private Paint mRipplePaint = new Paint();
private boolean isStartRipple;
private int rippleFirstRadius = 0;
private int rippleSecondRadius = -33;
private int rippleThirdRadius = -66;
private Paint textPaint = new Paint();
private String mText="扫描中...";
private int mDefaultColor = Color.parseColor("#54FF9F");
private int mColor = mDefaultColor;
private int mDefaultTextColor = Color.WHITE;
private int mTextColor = mDefaultTextColor;
private float mDefaultTextSize = 26;
private float mTextSize = mDefaultTextSize;
private int mDefaultWidth = 300;
private Handler handler = new Handler();

/**
* @param context
*/
public WaveView(Context context) {
super(context);
init(context);
}
/**
* @param context
* @param attrs
*/
public WaveView(Context context, AttributeSet attrs) {
super(context, attrs);
getAttrs(context, attrs);
init(context);
}
/**
* @param context
* @param attrs
* @param defStyleAttr
*/
public WaveView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
getAttrs(context, attrs);
init(context);
}

private void getAttrs(Context context, AttributeSet attrs) {
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.waveView);
for(int i = 0; i < a.getIndexCount(); i++) {
int attrIndex = a.getIndex(i);
switch (attrIndex) {
case R.styleable.waveView_text:
mText = a.getString(attrIndex);
break;
case R.styleable.waveView_textColor:
mTextColor = a.getColor(attrIndex, mDefaultTextColor);
break;
case R.styleable.waveView_textSize:
mTextSize = a.getDimension(attrIndex, mDefaultTextSize);
break;
case R.styleable.waveView_color:
mColor = a.getColor(attrIndex, mDefaultColor);
break;
}
}
a.recycle();
}

private void init(Context context) {
mRipplePaint.setColor(mColor);
mRipplePaint.setAntiAlias(true);
mRipplePaint.setStyle(Paint.Style.FILL);
textPaint.setTextSize(mTextSize);
textPaint.setAntiAlias(true);
textPaint.setStyle(Paint.Style.FILL);
textPaint.setColor(mTextColor);
}

@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
}

@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
if(handler != null) {
handler.removeCallbacksAndMessages(null);
handler = null;
}
}

private Runnable mRunnable = new Runnable() {
@Override
public void run() {
invalidate();
if (isStartRipple) {
rippleFirstRadius++;
if (rippleFirstRadius > 100) {
rippleFirstRadius = 0;
}
rippleSecondRadius++;
if (rippleSecondRadius > 100) {
rippleSecondRadius = 0;
}
rippleThirdRadius++;
if (rippleThirdRadius > 100) {
rippleThirdRadius = 0;
}
}
if(handler != null) {
handler.postDelayed(mRunnable, 1);
}
}
};

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// TODO Auto-generated method stub
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int measureWidth = 0;
int measureHeight = 0;
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
measureWidth = widthSize;
measureHeight = heightSize;
if(widthMode == MeasureSpec.AT_MOST) {
measureWidth = mDefaultWidth;
}
if(heightMode == MeasureSpec.AT_MOST) {
measureHeight = mDefaultWidth;
}
mRippleViewWidth = Math.min(measureWidth, measureHeight);
float f1 = 7 * mRippleViewWidth / 20;
mRippleViewRadius = (mRippleViewWidth - (2*(int)(Math.floor(f1))))/2 ;
setMeasuredDimension(mRippleViewWidth, mRippleViewWidth);
}

@Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);
if (isStartRipple) {
float f1 = 7 * mRippleViewWidth / 20;
mRipplePaint.setAlpha(255);
//固定半径的圆形
canvas.drawCircle(mRippleViewWidth / 2, mRippleViewWidth / 2,
mRippleViewRadius, mRipplePaint);
//第一个扩散的圆形
int i1 = (int) (220.0F - (220.0F - 0.0F) / 100.0F
* rippleFirstRadius);
mRipplePaint.setAlpha(i1);
canvas.drawCircle(mRippleViewWidth / 2, mRippleViewWidth / 2,
mRippleViewRadius + f1 * rippleFirstRadius / 100.0F - 2,
mRipplePaint);
//第二个扩散的圆形
if (rippleSecondRadius >= 0) {
int i3 = (int) (220.0F - (220.0F - 0.0F) / 100.0F
* rippleSecondRadius);
mRipplePaint.setAlpha(i3);
canvas.drawCircle(mRippleViewWidth / 2, mRippleViewWidth / 2,
mRippleViewRadius + f1 * rippleSecondRadius / 100.0F - 2,
mRipplePaint);
}
//第三个扩散的圆形
if (rippleThirdRadius >= 0) {
int i2 = (int) (220.0F - (220.0F - 0.0F) / 100.0F
* rippleThirdRadius);
mRipplePaint.setAlpha(i2);
canvas.drawCircle(mRippleViewWidth / 2, mRippleViewWidth / 2,
mRippleViewRadius + f1 * rippleThirdRadius / 100.0F -2,
mRipplePaint);
}
}
float length = textPaint.measureText(mText);
canvas.drawText(mText, (mRippleViewWidth - length) / 2,
mRippleViewWidth / 2 + 5, textPaint);
}

public void stratWave() {
isStartRipple = true;
handler.post(mRunnable);
}
}

一共画了三个不断扩散的圆形。用了R的二十分之六的宽度作为第一个固定圆形的半径,三个圆形从固定半径向两边增大至R。三个圆形从里到外的时间相隔33个单位,透明度是从220递减到0。减去2是为了扩散的效果更好看一点。

布局

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:gravity="center"
android:layout_width="match_parent"
android:layout_height="match_parent">

<com.christmas.stickyheaderview.WaveView
android:id="@+id/rippleview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerInParent="true"
app:text="正在扫描中啦"/>

</LinearLayout>

WaveActivity.java中使用

1
2
mWaveView =(WaveView) findViewById(R.id.rippleview);
mWaveView.stratWave();