-
Notifications
You must be signed in to change notification settings - Fork 191
Expand file tree
/
Copy pathCircularProgressDrawable.java
More file actions
431 lines (396 loc) · 12.5 KB
/
CircularProgressDrawable.java
File metadata and controls
431 lines (396 loc) · 12.5 KB
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
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
/*
* Copyright (C) 2014 Saúl Díaz
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sefford.circularprogressdrawable;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
/**
* Circular Progress Drawable.
* <p/>
* This drawable will produce a circular shape with a ring surrounding it. The ring can appear
* both filled and give a little cue when it is empty.
* <p/>
* The inner circle size, the progress of the outer ring and if it is loading parameters can be
* controlled, as well the different colors for the three components.
*
* @author Saul Diaz <sefford@gmail.com>
*/
public class CircularProgressDrawable extends Drawable {
/**
* Factor to convert the factor to paint the arc.
* <p/>
* In this way the developer can use a more user-friendly [0..1f] progress
*/
public static final int PROGRESS_FACTOR = -360;
/**
* Property Inner Circle Scale.
* <p/>
* The inner ring is supposed to defaults stay 3/4 radius off the outer ring at (75% scale), but this
* property can make it grow or shrink via this equation: OuterRadius * Scale.
* <p/>
* A 100% scale will make the inner circle to be the same radius as the outer ring.
*/
public static final String CIRCLE_SCALE_PROPERTY = "circleScale";
/**
* Property Progress of the outer circle.
* <p/>
* The progress of the circle. If {@link #setIndeterminate(boolean) indeterminate flag} is set
* to FALSE, this property will be used to indicate the completion of the outer circle [0..1f].
* <p/>
* If set to TRUE, the drawable will activate the loading mode, where the drawable will
* show a 90º arc which will be spinning around the outer circle as much as progress goes.
*/
public static final String PROGRESS_PROPERTY = "progress";
/**
* Property Ring color.
* <p/>
* Changes the ring filling color
*/
public static final String RING_COLOR_PROPERTY = "ringColor";
/**
* Property circle color.
* <p/>
* Changes the inner circle color
*/
public static final String CIRCLE_COLOR_PROPERTY = "circleColor";
/**
* Property outline color.
* <p/>
* Changes the outline of the ring color.
*/
public static final String OUTLINE_COLOR_PROPERTY = "outlineColor";
/**
* Logger Tag for Logging purposes.
*/
public static final String TAG = "CircularProgressDrawable";
/**
* Paint object to draw the element.
*/
private final Paint paint;
/**
* Ring progress.
*/
protected float progress;
/**
* Color for the empty outer ring.
*/
protected int outlineColor;
/**
* Color for the completed ring.
*/
protected int ringColor;
/**
* Color for the inner circle.
*/
protected int centerColor;
/**
* Rectangle where the filling ring will be drawn into.
*/
protected final RectF arcElements;
/**
* Width of the filling ring.
*/
protected final int ringWidth;
/**
* Scale of the inner circle. It will affect the inner circle size on this equation:
* ([Biggest length of the Drawable] / 2) - (ringWidth / 2) * scale.
*/
protected float circleScale;
/**
* Set if it is an indeterminate
*/
protected boolean indeterminate;
/**
* Creates a new CouponDrawable.
*
* @param ringWidth Width of the filled ring
* @param circleScale Scale difference between the outer ring and the inner circle
* @param outlineColor Color for the outline color
* @param ringColor Color for the filled ring
* @param centerColor Color for the center element
*/
CircularProgressDrawable(int ringWidth, float circleScale, int outlineColor, int ringColor, int centerColor) {
this.progress = 0;
this.outlineColor = outlineColor;
this.ringColor = ringColor;
this.centerColor = centerColor;
this.paint = new Paint();
this.paint.setAntiAlias(true);
this.ringWidth = ringWidth;
this.arcElements = new RectF();
this.circleScale = circleScale;
this.indeterminate = false;
}
@Override
public void draw(Canvas canvas) {
draw(canvas, 0);
}
/**
*
* @param canvas
* @param size of the circle. If <= 0 then circle fill whole canvas
*/
protected void draw(Canvas canvas, int size) {
final Rect bounds = getBounds();
if(size <= 0){
size = Math.min(bounds.height(), bounds.width());
}
float outerRadius = (size / 2) - (ringWidth / 2);
float innerRadius = outerRadius * circleScale;
float offsetX = (bounds.width() - outerRadius * 2) / 2;
float offsetY = (bounds.height() - outerRadius * 2) / 2;
// Outline Circle
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(1);
paint.setColor(outlineColor);
canvas.drawCircle(bounds.centerX(), bounds.centerY(), outerRadius, paint);
// Inner circle
paint.setStyle(Paint.Style.FILL);
paint.setColor(centerColor);
canvas.drawCircle(bounds.centerX(), bounds.centerY(), innerRadius, paint);
int halfRingWidth = ringWidth / 2;
float arcX0 = offsetX + halfRingWidth;
float arcY0 = offsetY + halfRingWidth;
float arcX = offsetX + outerRadius * 2 - halfRingWidth;
float arcY = offsetY + outerRadius * 2 - halfRingWidth;
// Outer Circle
paint.setColor(ringColor);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(ringWidth);
paint.setStrokeCap(Paint.Cap.ROUND);
arcElements.set(arcX0, arcY0, arcX, arcY);
if (indeterminate) {
canvas.drawArc(arcElements, progress, 90, false, paint);
} else {
canvas.drawArc(arcElements, 89, progress, false, paint);
}
}
@Override
public void setAlpha(int alpha) {
paint.setAlpha(alpha);
}
@Override
public void setColorFilter(ColorFilter cf) {
paint.setColorFilter(cf);
}
@Override
public int getOpacity() {
return 1 - paint.getAlpha();
}
/**
* Returns the progress of the outer ring.
* <p/>
* Will output a correct value only when the indeterminate mode is set to FALSE.
*
* @return Progress of the outer ring.
*/
public float getProgress() {
return progress / PROGRESS_FACTOR;
}
/**
* Sets the progress [0..1f]
*
* @param progress Sets the progress
*/
public void setProgress(float progress) {
if (indeterminate) {
this.progress = progress;
} else {
this.progress = PROGRESS_FACTOR * progress;
}
invalidateSelf();
}
/**
* Returns the inner circle scale.
*
* @return Inner circle scale in float multiplier.
*/
public float getCircleScale() {
return circleScale;
}
/**
* Sets the inner circle scale.
*
* @param circleScale Inner circle scale.
*/
public void setCircleScale(float circleScale) {
this.circleScale = circleScale;
invalidateSelf();
}
/**
* Get the indeterminate status of the Drawable
*
* @return TRUE if the Drawable is in indeterminate mode or FALSE if it is in progress mode.
*/
public boolean isIndeterminate() {
return indeterminate;
}
/**
* Sets the indeterminate parameter.
* <p/>
* The indeterminate parameter will change the behavior of the Drawable. If the indeterminate
* mode is set to FALSE, the outer ring will be able to be filled by using {@link #setProgress(float) setProgress}.
* <p/>
* Otherwise the drawable will enter "loading mode" and a 90º arc will be able to be spinned around
* the inner circle.
* <p/>
* <b>By default, indeterminate mode is set to FALSE.</b>
*
* @param indeterminate TRUE to activate loading mode. FALSE to activate progress mode.
*/
public void setIndeterminate(boolean indeterminate) {
this.indeterminate = indeterminate;
}
/**
* Gets the outline color.
*
* @return Outline color of the empty ring.
*/
public int getOutlineColor() {
return outlineColor;
}
/**
* Gets the filled ring color.
*
* @return Returns the filled ring color.
*/
public int getRingColor() {
return ringColor;
}
/**
* Gets the color of the inner circle.
*
* @return Inner circle color.
*/
public int getCenterColor() {
return centerColor;
}
/**
* Sets the empty progress outline color.
*
* @param outlineColor Outline color in #AARRGGBB format.
*/
public void setOutlineColor(int outlineColor) {
this.outlineColor = outlineColor;
invalidateSelf();
}
/**
* Sets the progress ring color.
*
* @param ringColor Ring color in #AARRGGBB format.
*/
public void setRingColor(int ringColor) {
this.ringColor = ringColor;
invalidateSelf();
}
/**
* Sets the inner circle color.
*
* @param centerColor Inner circle color in #AARRGGBB format.
*/
public void setCenterColor(int centerColor) {
this.centerColor = centerColor;
invalidateSelf();
}
/**
* Helper class to manage the creation of a CircularProgressDrawable
*
* @author Saul Diaz <sefford@gmail.com>
*/
public static class Builder {
/**
* Witdh of the stroke of the filled ring
*/
int ringWidth;
/**
* Color of the outline of the empty ring in #AARRGGBB mode.
*/
int outlineColor;
/**
* Color of the filled ring in #AARRGGBB mode.
*/
int ringColor;
/**
* Color of the inner circle in #AARRGGBB mode.
*/
int centerColor;
/**
* Scale between the outer ring and the inner circle
*/
float circleScale = 0.75f;
/**
* Sets the ring width.
*
* @param ringWidth Default ring width
* @return This builder
*/
public Builder setRingWidth(int ringWidth) {
this.ringWidth = ringWidth;
return this;
}
/**
* Sets the default empty outer ring outline color.
*
* @param outlineColor Outline color in #AARRGGBB format.
* @return
*/
public Builder setOutlineColor(int outlineColor) {
this.outlineColor = outlineColor;
return this;
}
/**
* Sets the progress ring color.
*
* @param ringColor Ring color in #AARRGGBB format.
* @returns This Builder
*/
public Builder setRingColor(int ringColor) {
this.ringColor = ringColor;
return this;
}
/**
* Sets the inner circle color.
*
* @param centerColor Inner circle color in #AARRGGBB format.
* @return This builder
*/
public Builder setCenterColor(int centerColor) {
this.centerColor = centerColor;
return this;
}
/**
* Sets the inner circle scale. Defaults to 0.75.
*
* @param circleScale Inner circle scale.
* @return This builder
*/
public Builder setInnerCircleScale(float circleScale) {
this.circleScale = circleScale;
return this;
}
/**
* Creates a new CircularProgressDrawable with the requested parameters
*
* @return New CircularProgressDrawableInstance
*/
public CircularProgressDrawable create() {
return new CircularProgressDrawable(ringWidth, circleScale, outlineColor, ringColor, centerColor);
}
}
}