Skip to content

Commit bd582c6

Browse files
Add gradients support (close #1)
1 parent 6d00669 commit bd582c6

File tree

8 files changed

+187
-3
lines changed

8 files changed

+187
-3
lines changed

README.md

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ Simple but customizable view for displaying progress
3232
##### With background filling enabled/disabled
3333
<img src="art/background-filling-1.png" width="30%" /> <img src="art/background-filling-2.png" width="30%" /> <img src="art/background-filling-3.png" width="30%" />
3434

35+
##### With gradients [linear, sweep and radial] (details [here](#gradients))
36+
<img src="art/gradient_linear.png" width="30%" /> <img src="art/gradient_sweep.png" width="30%" /> <img src="art/gradient_radial.png" width="30%" />
37+
3538

3639
## How to use
3740

@@ -58,7 +61,9 @@ Add view to your layout:
5861
app:startAngle="270"
5962
app:textColor="#fffc59"
6063
app:textSize="14sp"
61-
app:fillBackground="false" />
64+
app:fillBackground="false"
65+
app:gradientType="linear"
66+
app:gradientEndColor="@color/colorAccent" />
6267
```
6368

6469
Since all attributes have default values, you can specify none of them. Thus following code also works:
@@ -106,6 +111,8 @@ circularProgress.getMaxProgress() // returns 10000
106111
| Progress cap | `app:progressCap` | setter: `setProgressStrokeCap(cap)`<br/>getter: `getProgressStrokeCap()` | `CAP_ROUND` |
107112
| Progress animation | `app:enableProgressAnimation` | setter: `setAnimationEnabled(enableAnimation)`<br/>getter: `isAnimationEnabled()` | `true` |
108113
| Whether to fill background with progress background color | `app:fillBackground` | setter: `setFillBackgroundEnabled(enable)`<br/>getter: `isFillBackgroundEnabled()` | `false` |
114+
| Gradient type | `app:gradientType` | setter: `setGradient(type, color)`<br/>getter: `getGradientType()` | `no_gradient` |
115+
| End color of a gradient | `app:gradientEndColor` | - | - |
109116

110117
---
111118

@@ -208,6 +215,38 @@ circularProgress.setInterpolator(new LinearInterpolator());
208215

209216
---
210217

218+
#### Gradients
219+
`CircularProgressIndicator` supports 3 types of gradient:
220+
- Linear
221+
- Radial (doesn't look really good)
222+
- Sweep
223+
224+
They can be setup using attribute `app:gradientType"` that accepts 4 values:
225+
- `linear`
226+
- `radial`
227+
- `sweep`
228+
- `no_gradient`- default one, can also be used to remove gradient
229+
You also must specify end color using `app:gradientEndColor="color|reference"` attribute.
230+
231+
Or you can set it in code:
232+
```java
233+
int endColor = Color.MAGENTA;
234+
235+
/* Must be one of:
236+
* - LINEAR_GRADIENT
237+
* - RADIAL_GRADIENT
238+
* - SWEEP_GRADIENT
239+
* - NO_GRADIENT
240+
* */
241+
int gradientType = CircularProgressIndicator.LINEAR_GRADIENT;
242+
243+
circularProgress.setGradient(gradientType, endColor);
244+
245+
circularProgress.getGradientType(); //returns LINEAR_GRADIENT
246+
```
247+
248+
---
249+
211250
### Download using Gradle
212251

213252
Add this in your root `build.gradle` at the end of `repositories` in `allprojects` section:

art/gradient_linear.png

211 KB
Loading

art/gradient_radial.png

272 KB
Loading

art/gradient_sweep.png

211 KB
Loading

circularprogressindicator/src/main/java/antonkozyriatskyi/circularprogressindicator/CircularProgressIndicator.java

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,14 @@
99
import android.content.res.TypedArray;
1010
import android.graphics.Canvas;
1111
import android.graphics.Color;
12+
import android.graphics.LinearGradient;
13+
import android.graphics.Matrix;
1214
import android.graphics.Paint;
15+
import android.graphics.RadialGradient;
1316
import android.graphics.Rect;
1417
import android.graphics.RectF;
18+
import android.graphics.Shader;
19+
import android.graphics.SweepGradient;
1520
import android.os.Build;
1621
import android.support.annotation.ColorInt;
1722
import android.support.annotation.Dimension;
@@ -43,6 +48,11 @@ public class CircularProgressIndicator extends View {
4348
public static final int CAP_ROUND = 0;
4449
public static final int CAP_BUTT = 1;
4550

51+
public static final int NO_GRADIENT = 0;
52+
public static final int LINEAR_GRADIENT = 1;
53+
public static final int RADIAL_GRADIENT = 2;
54+
public static final int SWEEP_GRADIENT = 3;
55+
4656
private static final int DEFAULT_PROGRESS_START_ANGLE = 270;
4757
private static final int ANGLE_START_PROGRESS_BACKGROUND = 0;
4858
private static final int ANGLE_END_PROGRESS_BACKGROUND = 360;
@@ -170,6 +180,22 @@ private void init(@NonNull Context context, @Nullable AttributeSet attrs) {
170180

171181
reformatProgressText();
172182

183+
final int gradientType = a.getColor(R.styleable.CircularProgressIndicator_gradientType, 0);
184+
if (gradientType != NO_GRADIENT) {
185+
final int gradientColorEnd = a.getColor(R.styleable.CircularProgressIndicator_gradientEndColor, -1);
186+
187+
if (gradientColorEnd == -1) {
188+
throw new IllegalArgumentException("did you forget to specify gradientColorEnd?");
189+
}
190+
191+
post(new Runnable() {
192+
@Override
193+
public void run() {
194+
setGradient(gradientType, gradientColorEnd);
195+
}
196+
});
197+
}
198+
173199
a.recycle();
174200
}
175201

@@ -269,6 +295,11 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
269295
@Override
270296
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
271297
calculateBounds(w, h);
298+
299+
Shader shader = progressPaint.getShader();
300+
if (shader instanceof RadialGradient) {
301+
RadialGradient gradient = (RadialGradient) shader;
302+
}
272303
}
273304

274305
private void calculateBounds(int w, int h) {
@@ -674,6 +705,54 @@ public Interpolator getInterpolator() {
674705
return animationInterpolator;
675706
}
676707

708+
public void setGradient(@GradientType int type, @ColorInt int endColor) {
709+
Shader gradient = null;
710+
711+
float cx = getWidth() / 2f;
712+
float cy = getHeight() / 2f;
713+
714+
int startColor = progressPaint.getColor();
715+
716+
switch (type) {
717+
case LINEAR_GRADIENT:
718+
gradient = new LinearGradient(0f, 0f, getWidth(), getHeight(), startColor, endColor, Shader.TileMode.CLAMP);
719+
break;
720+
case RADIAL_GRADIENT:
721+
gradient = new RadialGradient(cx, cy, cx, startColor, endColor, Shader.TileMode.MIRROR);
722+
break;
723+
case SWEEP_GRADIENT:
724+
gradient = new SweepGradient(cx, cy, new int[]{startColor, endColor}, null);
725+
break;
726+
}
727+
728+
if (gradient != null) {
729+
Matrix matrix = new Matrix();
730+
matrix.postRotate(startAngle, cx, cy);
731+
gradient.setLocalMatrix(matrix);
732+
}
733+
734+
progressPaint.setShader(gradient);
735+
736+
invalidate();
737+
}
738+
739+
@GradientType
740+
public int getGradientType() {
741+
Shader shader = progressPaint.getShader();
742+
743+
int type = NO_GRADIENT;
744+
745+
if (shader instanceof LinearGradient) {
746+
type = LINEAR_GRADIENT;
747+
} else if (shader instanceof RadialGradient) {
748+
type = RADIAL_GRADIENT;
749+
} else if (shader instanceof SweepGradient) {
750+
type = SWEEP_GRADIENT;
751+
}
752+
753+
return type;
754+
}
755+
677756
@Retention(RetentionPolicy.SOURCE)
678757
@IntDef({DIRECTION_CLOCKWISE, DIRECTION_COUNTERCLOCKWISE})
679758
public @interface Direction {
@@ -684,6 +763,11 @@ public Interpolator getInterpolator() {
684763
public @interface Cap {
685764
}
686765

766+
@Retention(RetentionPolicy.SOURCE)
767+
@IntDef({NO_GRADIENT, LINEAR_GRADIENT, RADIAL_GRADIENT, SWEEP_GRADIENT})
768+
public @interface GradientType {
769+
}
770+
687771
public interface ProgressTextAdapter {
688772

689773
@NonNull

circularprogressindicator/src/main/res/values/attrs.xml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,14 @@
3232

3333
<attr name="fillBackground" format="boolean" />
3434

35+
<attr name="gradientEndColor" format="color|reference"/>
36+
<attr name="gradientType" format="enum">
37+
<enum name="no_gradient" value="0"/>
38+
<enum name="linear" value="1"/>
39+
<enum name="radial" value="2"/>
40+
<enum name="sweep" value="3"/>
41+
</attr>
42+
3543
</declare-styleable>
3644

3745
</resources>

example/src/main/java/antonkozyriatskyi/circularprogressindicatorexample/MainActivity.java

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,19 @@
55
import android.support.v7.app.AppCompatActivity;
66
import android.util.Log;
77
import android.view.View;
8+
import android.widget.AdapterView;
89
import android.widget.Button;
910
import android.widget.CheckBox;
1011
import android.widget.CompoundButton;
1112
import android.widget.RadioGroup;
1213
import android.widget.SeekBar;
14+
import android.widget.SimpleAdapter;
15+
import android.widget.Spinner;
1316
import android.widget.Switch;
1417

18+
import java.util.ArrayList;
19+
import java.util.HashMap;
20+
1521
import antonkozyriatskyi.circularprogressindicator.CircularProgressIndicator;
1622

1723

@@ -106,6 +112,50 @@ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
106112
circularProgress.setAnimationEnabled(isChecked);
107113
}
108114
});
115+
116+
Spinner gradientType = findViewById(R.id.sp_gradient_type);
117+
118+
final ArrayList<HashMap<String, String>> gradients = new ArrayList<>();
119+
HashMap<String, String> gradient = new HashMap<>();
120+
gradient.put("type", "No gradient");
121+
gradient.put("value", "0");
122+
gradients.add(gradient);
123+
124+
gradient = new HashMap<>();
125+
gradient.put("type", "Linear");
126+
gradient.put("value", "1");
127+
gradients.add(gradient);
128+
129+
gradient = new HashMap<>();
130+
gradient.put("type", "Radial");
131+
gradient.put("value", "2");
132+
gradients.add(gradient);
133+
134+
gradient = new HashMap<>();
135+
gradient.put("type", "Sweep");
136+
gradient.put("value", "3");
137+
gradients.add(gradient);
138+
139+
140+
gradientType.setAdapter(
141+
new SimpleAdapter(
142+
this,
143+
gradients,
144+
android.R.layout.simple_dropdown_item_1line,
145+
new String[]{"type"},
146+
new int[]{android.R.id.text1}
147+
));
148+
149+
gradientType.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
150+
@Override
151+
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
152+
circularProgress.setGradient(Integer.parseInt(gradients.get(position).get("value")), Color.MAGENTA);
153+
}
154+
155+
@Override
156+
public void onNothingSelected(AdapterView<?> parent) {
157+
}
158+
});
109159
}
110160

111161
@Override
@@ -154,12 +204,10 @@ public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
154204

155205
@Override
156206
public void onStartTrackingTouch(SeekBar seekBar) {
157-
158207
}
159208

160209
@Override
161210
public void onStopTrackingTouch(SeekBar seekBar) {
162-
163211
}
164212

165213
@Override

example/src/main/res/layout/activity_main.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,11 @@
160160
android:checked="true"
161161
android:text="Enable animation" />
162162

163+
<Spinner
164+
android:id="@+id/sp_gradient_type"
165+
android:layout_width="match_parent"
166+
android:layout_height="wrap_content"/>
167+
163168
<Button
164169
android:id="@+id/btn_progress_color"
165170
android:layout_width="match_parent"

0 commit comments

Comments
 (0)