Simple but customizable view for displaying progress
With custom progress text (more examples here)
With custom start angle (details here)
With custom progress cap (details here)
With gradients [linear, sweep and radial] (details here)
Add view to your layout:
<antonkozyriatskyi.circularprogressindicator.CircularProgressIndicator
android:id="@+id/circular_progress"
android:layout_width="200dp"
android:layout_height="200dp"
android:layout_gravity="center"
android:layout_marginBottom="8dp"
android:layout_marginTop="8dp"
app:direction="clockwise"
app:dotColor="?colorPrimary"
app:dotWidth="16dp"
app:drawDot="true"
app:enableProgressAnimation="true"
app:formattingPattern="%d"
app:progressBackgroundColor="?colorAccent"
app:progressBackgroundStrokeWidth="8dp"
app:progressCap="round"
app:progressColor="?colorPrimary"
app:progressStrokeWidth="16dp"
app:startAngle="270"
app:textColor="#fffc59"
app:textSize="14sp"
app:fillBackground="false"
app:gradientType="linear"
app:gradientEndColor="@color/colorAccent" />
Since all attributes have default values, you can specify none of them. Thus following code also works:
<antonkozyriatskyi.circularprogressindicator.CircularProgressIndicator
android:id="@+id/circular_progress"
android:layout_width="200dp"
android:layout_height="200dp"
android:layout_gravity="center"
android:layout_marginBottom="8dp"
android:layout_marginTop="8dp" />
Than find it in code and set progress:
CircularProgressIndicator circularProgress = findViewById(R.id.circular_progress);
// you can set max and current progress values individually
circularProgress.setMaxProgress(10000);
circularProgress.setCurrentProgress(5000);
// or all at once
circularProgress.setProgress(5000, 10000);
// you can get progress values using following getters
circularProgress.getProgress() // returns 5000
circularProgress.getMaxProgress() // returns 10000
// you can also set a visual gap between the progress and background strokes
circularProgress.setProgressGap(100);
Description | XML | Java | Default value |
---|---|---|---|
Progress color | app:progressColor |
setter: setProgressColor(color) getter: getProgressColor() |
#3f51b5 |
Progress background color | app:progressBackgroundColor |
setter: setProgressBackgroundColor(color) getter: getProgressBackgroundColor() |
#e0e0e0 |
Width of progress stroke | app:progressStrokeWidth |
setters: setProgressStrokeWidthDp(widthInDp) or setProgressStrokeWidthPx(widthInPx) getter: getProgressStrokeWidth() (returns width in pixels) |
8dp |
Width of progress background stroke | app:progressBackgroundStrokeWidth |
setters: setProgressBackgroundStrokeWidthDp(widthInDp) or setProgressBackgroundStrokeWidthPx(widthInPx) getter: getProgressBackgroundStrokeWidth() (returns width in pixels) |
same as progress width |
Whether to draw dot. true or false |
app:drawDot |
setter: setShouldDrawDot(shoulDrawDot) getter: isDotEnabled() |
true |
Dot color | app:dotColor |
setter: setDotColor(dotColor) getter: getDotColor() |
same as progress color |
Dot width | app:dotWidth |
setters: setDotWidthDp(widthInDp) or setDotWidthPx(widthInPx) getter: getDotWidth() (returns width in pixels) |
same as progress stroke width |
Progress text size | app:textSize |
setters: setTextSizeSp(sizeInSp) or setTextSizePx(sizeInPx) getter: getTextSize() (returns size in pixels) |
24sp |
Progress text color | app:textColor |
setter: setTextColor(textColor) getter: getTextColor() |
same as progress color |
Whether to show text | app:showText |
setter: setShowTextEnabled(enabled) getter: isShowTextEnabled() |
true |
Formatting pattern to be used in PatternProgressTextAdapter . Checkout Formatting progress text section. |
app:formattingPattern |
setter: setProgressTextAdapter(progressTextAdapter) getter: getProgressTextAdapter() |
not specified |
Direction of the progress arc (clockwise or counterclockwise ) |
app:direction |
setter: setDirection(direction) getter: getDirection() |
counterclockwise |
Start angle. Checkout Start angle section. | app:startAngle |
setter: setStartAngle(startAngle) getter: getStartAngle() |
270 |
Progress cap | app:progressCap |
setter: setProgressStrokeCap(cap) getter: getProgressStrokeCap() |
CAP_ROUND |
Progress animation | app:enableProgressAnimation |
setter: setAnimationEnabled(enableAnimation) getter: isAnimationEnabled() |
true |
Whether to fill background with progress background color | app:fillBackground |
setter: setFillBackgroundEnabled(enable) getter: isFillBackgroundEnabled() |
false |
Gradient type | app:gradientType |
setter: setGradient(type, color) getter: getGradientType() |
no_gradient |
End color of a gradient | app:gradientEndColor |
- | - |
Before version 1.0.5 formatting text was limited to specifying prefix, suffix and delimiter. Since version 1.1 you have full control over the text to be displayed (thanks to the repitch for the idea and implementation).
!!! Attributes app:useProgressTextDelimiter
, app:progressTextDelimiter
, app:progressTextPrefix
, app:progressTextSuffix
were removed in v1.1.3.
The only thing you have to do is to provide an implementation of CircularProgressIndicator.ProgressTextAdapter
.
You must override it's String formatText(double currentProgress);
method.
Library already provides you with two implementations:
- DefaultProgressTextAdapter that just returns string representation of the progress value cast to
int
. - PatternProgressTextAdapter that uses pattern specified in
formattingPattern
attribute to format progress (if it is set, otherwise it falls back to theDefaultProgressTextAdapter
).
DefaultProgressTextAdapter
is a default text adapter, which is used when no formatterPattern
attribute set or progressIndicator.setProgressTextAdapter(null)
method was called.
It's implementation looks like this:
@Override
public String formatText(double currentProgress) {
return String.valueOf((int) currentProgress);
}
PatternProgressTextAdapter
supports formatting progress using Java's formatting patterns.
For example, if you want to display progress with two digits for the fractional part, you can use %.2f
pattern and set it via
-
attribute:
app:formattingPattern="@string/pattern"
that refers to a string resource<string name="pattern">%.2f</string>
If you don't want to use string resource - you have to use unicode for percent sign (%
) instead of sign itself:
app:formattingPattern="%.2f"
-
or
PatternProgressTextAdapter
:circularProgress.setProgressTextAdapter(new PatternProgressTextAdapter("%.2f"));
Here is the example of TimeTextAdapter
by repitch that displays text in format of 'HH.MM.SS'
private static final CircularProgressIndicator.ProgressTextAdapter TIME_TEXT_ADAPTER = new CircularProgressIndicator.ProgressTextAdapter() {
@Override
public String formatText(double time) {
int hours = (int) (time / 3600);
time %= 3600;
int minutes = (int) (time / 60);
int seconds = (int) (time % 60);
StringBuilder sb = new StringBuilder();
if (hours < 10) {
sb.append(0);
}
sb.append(hours).append(":");
if (minutes < 10) {
sb.append(0);
}
sb.append(minutes).append(":");
if (seconds < 10) {
sb.append(0);
}
sb.append(seconds);
return sb.toString();
}
};
If you don't want any text to be displayed - just create your own ProgressTextAdapter
that returns an empty string.
You can specify start angle for the progress arc using app:startAngle
attribute or setStartAngle(startAngle)
method.
Acceptable values are from 0 to 360 degrees. But be aware that they go clockwise, so:
- 0° is at 3 o'clock as usual
- 90° is at 6 o'clock
- 180° is at 9 o'clock
- 270° is at 12 o'clock
Image taken from Android Canvas' drawArc Method: A Visual Guide article.
circularProgress.setOnProgressChangeListener(new CircularProgressIndicator.OnProgressChangeListener() {
@Override
public void onProgressChanged(double progress, double maxProgress) {
Log.d("PROGRESS", String.format("Current: %1$.0f, max: %2$.0f", progress, maxProgress));
}
});
Default interpolator used for running animation is AccelerateDecelerateInterpolator
,
but you can set any other one using setter:
circularProgress.setInterpolator(new LinearInterpolator());
CircularProgressIndicator
supports 3 types of gradient:
- Linear
- Radial (doesn't look really good)
- Sweep
They can be setup using attribute app:gradientType"
that accepts 4 values:
linear
radial
sweep
no_gradient
- default one, can also be used to remove gradient You also must specify end color usingapp:gradientEndColor="color|reference"
attribute.
Or you can set it in code:
int endColor = Color.MAGENTA;
/* Must be one of:
* - LINEAR_GRADIENT
* - RADIAL_GRADIENT
* - SWEEP_GRADIENT
* - NO_GRADIENT
* */
int gradientType = CircularProgressIndicator.LINEAR_GRADIENT;
circularProgress.setGradient(gradientType, endColor);
circularProgress.getGradientType(); //returns LINEAR_GRADIENT
Or, for advanced gradients with multiple colors and optional color positions, in code:
circularProgress.setGradient(type, new int[]{Color.BLUE, Color.MAGENTA, Color.RED}, new float[]{0f, .3f, .7f});
Add this in your root build.gradle
at the end of repositories
in allprojects
section:
allprojects {
repositories {
maven { url 'https://jitpack.io' }
}
}
Then add this dependency to your module-level build.gradle
in dependencies
section:
implementation 'com.github.antonKozyriatskyi:CircularProgressIndicator:1.3.0'
If you have any troubles downloading the library - checkout issue#5
Copyright 2018 Anton Kozyriatskyi
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.