-
Notifications
You must be signed in to change notification settings - Fork 70
/
WaveProgressView.java
293 lines (240 loc) · 10.4 KB
/
WaveProgressView.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
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
package com.anlia.progressbar;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.LinearInterpolator;
import android.view.animation.Transformation;
import android.widget.TextView;
import com.anlia.utils.DpOrPxUtils;
/**
* Created by anlia on 2017/10/16.
*/
public class WaveProgressView extends View {
private Paint circlePaint;//圆形进度框画笔
private Paint wavePaint;//绘制波浪画笔
private Path wavePath;//绘制波浪Path
private Paint secondWavePaint;//绘制第二个波浪的画笔
private Bitmap bitmap;//缓存bitmap
private Canvas bitmapCanvas;
private WaveProgressAnim waveProgressAnim;
private TextView textView;
private OnAnimationListener onAnimationListener;
private float waveWidth;//波浪宽度
private float waveHeight;//波浪高度
private int waveNum;//波浪组的数量(一次起伏为一组)
private float waveMovingDistance;//波浪平移的距离
private int viewSize;//重新测量后View实际的宽高
private int defaultSize;//自定义View默认的宽高
private float percent;//进度条占比
private float progressNum;//可以更新的进度条数值
private float maxNum;//进度条最大值
private int waveColor;//波浪颜色
private int secondWaveColor;//第二层波浪颜色
private int bgColor;//背景进度框颜色
private boolean isDrawSecondWave;
public WaveProgressView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init(context,attrs);
}
private void init(Context context,AttributeSet attrs){
TypedArray typedArray = context.obtainStyledAttributes(attrs,R.styleable.WaveProgressView);
waveWidth = typedArray.getDimension(R.styleable.WaveProgressView_wave_width,DpOrPxUtils.dip2px(context,25));
waveHeight = typedArray.getDimension(R.styleable.WaveProgressView_wave_height,DpOrPxUtils.dip2px(context,5));
waveColor = typedArray.getColor(R.styleable.WaveProgressView_wave_color,Color.GREEN);
secondWaveColor = typedArray.getColor(R.styleable.WaveProgressView_second_wave_color,getResources().getColor(R.color.light));
bgColor = typedArray.getColor(R.styleable.WaveProgressView_wave_bg_color,Color.GRAY);
typedArray.recycle();
defaultSize = DpOrPxUtils.dip2px(context,100);
waveNum =(int) Math.ceil(Double.parseDouble(String.valueOf(defaultSize / waveWidth / 2)));
waveMovingDistance = 0;
wavePath = new Path();
wavePaint = new Paint();
wavePaint.setColor(waveColor);
wavePaint.setAntiAlias(true);//设置抗锯齿
wavePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
secondWavePaint = new Paint();
secondWavePaint.setColor(secondWaveColor);
secondWavePaint.setAntiAlias(true);//设置抗锯齿
secondWavePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP));//因为要覆盖在第一层波浪上,且要让半透明生效,所以选此模式
circlePaint = new Paint();
circlePaint.setColor(bgColor);
circlePaint.setAntiAlias(true);//设置抗锯齿
waveProgressAnim = new WaveProgressAnim();
waveProgressAnim.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {}
@Override
public void onAnimationEnd(Animation animation) {}
@Override
public void onAnimationRepeat(Animation animation) {
/*if(percent == progressNum / maxNum){
waveProgressAnim.setDuration(5000);
}*/
}
});
percent = 0;
progressNum = 0;
maxNum = 100;
isDrawSecondWave = false;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int height = measureSize(defaultSize, heightMeasureSpec);
int width = measureSize(defaultSize, widthMeasureSpec);
int min = Math.min(width, height);// 获取View最短边的长度
setMeasuredDimension(min, min);// 强制改View为以最短边为长度的正方形
viewSize = min;
waveNum =(int) Math.ceil(Double.parseDouble(String.valueOf(viewSize / waveWidth / 2)));
}
private int measureSize(int defaultSize,int measureSpec) {
int result = defaultSize;
int specMode = View.MeasureSpec.getMode(measureSpec);
int specSize = View.MeasureSpec.getSize(measureSpec);
if (specMode == View.MeasureSpec.EXACTLY) {
result = specSize;
} else if (specMode == View.MeasureSpec.AT_MOST) {
result = Math.min(result, specSize);
}
return result;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
bitmap = Bitmap.createBitmap(viewSize, viewSize, Bitmap.Config.ARGB_8888);
bitmapCanvas = new Canvas(bitmap);
bitmapCanvas.drawCircle(viewSize/2, viewSize/2, viewSize/2, circlePaint);
bitmapCanvas.drawPath(getWavePath(),wavePaint);
if(isDrawSecondWave){
bitmapCanvas.drawPath(getSecondWavePath(),secondWavePaint);
}
canvas.drawBitmap(bitmap, 0, 0, null);
}
private Path getWavePath(){
// float changeWaveHeight = (1 - percent) * waveHeight;
float changeWaveHeight = waveHeight;
if(onAnimationListener!=null){
changeWaveHeight =
onAnimationListener.howToChangeWaveHeight(percent,waveHeight) == 0 && percent < 1
?waveHeight
:onAnimationListener.howToChangeWaveHeight(percent,waveHeight);
}
wavePath.reset();
//移动到右上方,也就是p0点
wavePath.moveTo(viewSize, (1-percent)*viewSize);
//移动到右下方,也就是p1点
wavePath.lineTo(viewSize, viewSize);
//移动到左下边,也就是p2点
wavePath.lineTo(0, viewSize);
//移动到左上方,也就是p3点
//wavePath.lineTo(0, (1-percent)*viewSize);
wavePath.lineTo(-waveMovingDistance, (1-percent)*viewSize);
//从p3开始向p0方向绘制波浪曲线
for (int i=0;i<waveNum*2;i++){
wavePath.rQuadTo(waveWidth/2, changeWaveHeight, waveWidth, 0);
wavePath.rQuadTo(waveWidth/2, -changeWaveHeight, waveWidth, 0);
}
//将path封闭起来
wavePath.close();
return wavePath;
}
private Path getSecondWavePath(){
// float changeWaveHeight = (1 - percent) * waveHeight;
float changeWaveHeight = waveHeight;
if(onAnimationListener!=null){
changeWaveHeight =
onAnimationListener.howToChangeWaveHeight(percent,waveHeight) == 0 && percent < 1
?waveHeight
:onAnimationListener.howToChangeWaveHeight(percent,waveHeight);
}
wavePath.reset();
//移动到左上方,也就是p3点
wavePath.moveTo(0, (1-percent)*viewSize);
//移动到左下边,也就是p2点
wavePath.lineTo(0, viewSize);
//移动到右下方,也就是p1点
wavePath.lineTo(viewSize, viewSize);
//移动到右上方,也就是p0点
wavePath.lineTo(viewSize + waveMovingDistance, (1-percent)*viewSize);
//从p0开始向p3方向绘制波浪曲线
for (int i=0;i<waveNum*2;i++){
wavePath.rQuadTo(-waveWidth/2, changeWaveHeight, -waveWidth, 0);
wavePath.rQuadTo(-waveWidth/2, -changeWaveHeight, -waveWidth, 0);
}
//将path封闭起来
wavePath.close();
return wavePath;
}
public class WaveProgressAnim extends Animation {
public WaveProgressAnim(){}
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
super.applyTransformation(interpolatedTime, t);
if(percent < progressNum / maxNum){
percent = interpolatedTime * progressNum / maxNum;
if(textView !=null && onAnimationListener!=null){
textView.setText(onAnimationListener.howToChangeText(interpolatedTime, progressNum,maxNum));
}
}
waveMovingDistance = interpolatedTime * waveNum * waveWidth * 2;
postInvalidate();
}
}
/**
* 设置进度条数值
* @param progressNum 进度条数值
* @param time 动画持续时间
*/
public void setProgressNum(float progressNum, int time) {
this.progressNum = progressNum;
percent = 0;
waveProgressAnim.setDuration(time);
waveProgressAnim.setRepeatCount(-1);
waveProgressAnim.setInterpolator(new LinearInterpolator());
this.startAnimation(waveProgressAnim);
}
/**
* 是否绘制第二层波浪
* @param isDrawSecondWave
*/
public void setDrawSecondWave(boolean isDrawSecondWave) {
this.isDrawSecondWave = isDrawSecondWave;
}
/**
* 设置显示文字的TextView
* @param textView
*/
public void setTextView(TextView textView) {
this.textView = textView;
}
public interface OnAnimationListener {
/**
* 如何处理要显示的文字内容
* @param interpolatedTime 从0渐变成1,到1时结束动画
* @param updateNum 进度条数值
* @param maxNum 进度条最大值
* @return
*/
String howToChangeText(float interpolatedTime, float updateNum, float maxNum);
/**
* 如何处理波浪高度
* @param percent 进度占比
* @param waveHeight 波浪高度
* @return
*/
float howToChangeWaveHeight(float percent, float waveHeight);
}
public void setOnAnimationListener(OnAnimationListener onAnimationListener) {
this.onAnimationListener = onAnimationListener;
}
}