Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,18 @@

> Support gradient direction from center to side by Michael Lee. `app:cpb_progressbar_color_direction` and `app:cpb_background_progressbar_color_direction` support `center_to_horizontal` or `center_to_vertical`
> Now, change the implementation to jitpack.io to use that. The release version is right here at the badge.
>[![](https://jitpack.io/v/michaellee123/CircularProgressBar.svg)](https://jitpack.io/#michaellee123/CircularProgressBar)
>After this line, is the original document.Thanks to [Lopez Mikhael](https://github.com/lopspower).

---

<p align="center"><img src="/preview/header.png"></p>

CircularProgressBar
=================



<img src="/preview/preview.gif" alt="sample" title="sample" width="300" height="480" align="right" vspace="24" />

[![Platform](https://img.shields.io/badge/platform-android-green.svg)](http://developer.android.com/index.html)
Expand Down Expand Up @@ -51,12 +61,12 @@ You must use the following properties in your XML to change your CircularProgres
| `app:cpb_progressbar_color` | color | BLACK |
| `app:cpb_progressbar_color_start` | color | cpb_progressbar_color |
| `app:cpb_progressbar_color_end` | color | cpb_progressbar_color |
| `app:cpb_progressbar_color_direction` | left_to_right, right_to_left, top_to_bottom or bottom_to_top | left_to_right |
| `app:cpb_progressbar_color_direction` | left_to_right, right_to_left, top_to_bottom, bottom_to_top, center_to_horizontal or center_to_vertical | left_to_right |
| `app:cpb_progressbar_width` | dimension | 7dp |
| `app:cpb_background_progressbar_color` | color | GRAY |
| `app:cpb_background_progressbar_color_start` | color | GRAY |
| `app:cpb_background_progressbar_color_end` | color | GRAY |
| `app:cpb_background_progressbar_color_direction` | left_to_right, right_to_left, top_to_bottom or bottom_to_top | left_to_right |
| `app:cpb_background_progressbar_color_direction` | left_to_right, right_to_left, top_to_bottom, bottom_to_top, center_to_horizontal or center_to_vertical |
| `app:cpb_background_progressbar_width` | dimension | 3dp |
| `app:cpb_round_border` | boolean | false |
| `app:cpb_start_angle` | float | 0f (=top) |
Expand Down
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ buildscript {
classpath 'com.android.tools.build:gradle:4.2.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath 'com.github.ben-manes:gradle-versions-plugin:0.38.0'
classpath 'com.github.dcendents:android-maven-gradle-plugin:2.1'
}
}

Expand Down
17 changes: 12 additions & 5 deletions circularprogressbar-example/src/main/res/layout/activity_main.xml
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,18 @@
android:id="@+id/circularProgressBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:cpb_background_progressbar_color="#b6bbd8"
app:cpb_background_progressbar_width="10dp"
app:cpb_progress_direction="to_right"
app:cpb_progressbar_color="#3f51b5"
app:cpb_progressbar_width="20dp" />
app:cpb_background_progressbar_color_direction="center_to_vertical"
app:cpb_background_progressbar_color_end="#A0A8C3"
app:cpb_background_progressbar_color_start="#C0C6DF"
app:cpb_background_progressbar_width="15dp"
app:cpb_progress="100"
app:cpb_progress_direction="to_left"
app:cpb_progress_max="100"
app:cpb_progressbar_color_direction="center_to_horizontal"
app:cpb_progressbar_color_end="#6977C3"
app:cpb_progressbar_color_start="#030823"
app:cpb_progressbar_width="20dp"
app:cpb_round_border="true" />

</LinearLayout>

Expand Down
1 change: 1 addition & 0 deletions circularprogressbar/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,4 @@ dependencies {
}

apply from: rootProject.file('gradle/publish-mavencentral.gradle')
apply from: rootProject.file('gradle/publish-jitpack.gradle')
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ class CircularProgressBar(context: Context, attrs: AttributeSet? = null) : View(
requestLayout()
invalidate()
}
var backgroundProgressBarWidth: Float = resources.getDimension(R.dimen.default_background_stroke_width)
var backgroundProgressBarWidth: Float =
resources.getDimension(R.dimen.default_background_stroke_width)
set(value) {
field = value.dpToPx()
backgroundPaint.strokeWidth = field
Expand Down Expand Up @@ -172,7 +173,8 @@ class CircularProgressBar(context: Context, attrs: AttributeSet? = null) : View(
if (indeterminateMode) {
postIndeterminateModeHandler()
// whatever you want to do below
this@CircularProgressBar.progressDirectionIndeterminateMode = this@CircularProgressBar.progressDirectionIndeterminateMode.reverse()
this@CircularProgressBar.progressDirectionIndeterminateMode =
this@CircularProgressBar.progressDirectionIndeterminateMode.reverse()
if (this@CircularProgressBar.progressDirectionIndeterminateMode.isToRight()) {
setProgressWithAnimation(0f, 1500)
} else {
Expand All @@ -192,41 +194,71 @@ class CircularProgressBar(context: Context, attrs: AttributeSet? = null) : View(

private fun init(context: Context, attrs: AttributeSet?) {
// Load the styled attributes and set their properties
val attributes = context.theme.obtainStyledAttributes(attrs, R.styleable.CircularProgressBar, 0, 0)
val attributes =
context.theme.obtainStyledAttributes(attrs, R.styleable.CircularProgressBar, 0, 0)

// Value
progress = attributes.getFloat(R.styleable.CircularProgressBar_cpb_progress, progress)
progressMax = attributes.getFloat(R.styleable.CircularProgressBar_cpb_progress_max, progressMax)
progressMax =
attributes.getFloat(R.styleable.CircularProgressBar_cpb_progress_max, progressMax)

// StrokeWidth
progressBarWidth = attributes.getDimension(R.styleable.CircularProgressBar_cpb_progressbar_width, progressBarWidth).pxToDp()
backgroundProgressBarWidth = attributes.getDimension(R.styleable.CircularProgressBar_cpb_background_progressbar_width, backgroundProgressBarWidth).pxToDp()
progressBarWidth = attributes.getDimension(
R.styleable.CircularProgressBar_cpb_progressbar_width,
progressBarWidth
).pxToDp()
backgroundProgressBarWidth = attributes.getDimension(
R.styleable.CircularProgressBar_cpb_background_progressbar_width,
backgroundProgressBarWidth
).pxToDp()

// Color
progressBarColor = attributes.getInt(R.styleable.CircularProgressBar_cpb_progressbar_color, progressBarColor)
progressBarColor = attributes.getInt(
R.styleable.CircularProgressBar_cpb_progressbar_color,
progressBarColor
)
attributes.getColor(R.styleable.CircularProgressBar_cpb_progressbar_color_start, 0)
.also { if (it != 0) progressBarColorStart = it }
.also { if (it != 0) progressBarColorStart = it }
attributes.getColor(R.styleable.CircularProgressBar_cpb_progressbar_color_end, 0)
.also { if (it != 0) progressBarColorEnd = it }
progressBarColorDirection = attributes.getInteger(R.styleable.CircularProgressBar_cpb_progressbar_color_direction, progressBarColorDirection.value).toGradientDirection()
backgroundProgressBarColor = attributes.getInt(R.styleable.CircularProgressBar_cpb_background_progressbar_color, backgroundProgressBarColor)
attributes.getColor(R.styleable.CircularProgressBar_cpb_background_progressbar_color_start, 0)
.also { if (it != 0) backgroundProgressBarColorStart = it }
.also { if (it != 0) progressBarColorEnd = it }
progressBarColorDirection = attributes.getInteger(
R.styleable.CircularProgressBar_cpb_progressbar_color_direction,
progressBarColorDirection.value
).toGradientDirection()
backgroundProgressBarColor = attributes.getInt(
R.styleable.CircularProgressBar_cpb_background_progressbar_color,
backgroundProgressBarColor
)
attributes.getColor(
R.styleable.CircularProgressBar_cpb_background_progressbar_color_start,
0
)
.also { if (it != 0) backgroundProgressBarColorStart = it }
attributes.getColor(R.styleable.CircularProgressBar_cpb_background_progressbar_color_end, 0)
.also { if (it != 0) backgroundProgressBarColorEnd = it }
backgroundProgressBarColorDirection = attributes.getInteger(R.styleable.CircularProgressBar_cpb_background_progressbar_color_direction, backgroundProgressBarColorDirection.value).toGradientDirection()
.also { if (it != 0) backgroundProgressBarColorEnd = it }
backgroundProgressBarColorDirection = attributes.getInteger(
R.styleable.CircularProgressBar_cpb_background_progressbar_color_direction,
backgroundProgressBarColorDirection.value
).toGradientDirection()

// Progress Direction
progressDirection = attributes.getInteger(R.styleable.CircularProgressBar_cpb_progress_direction, progressDirection.value).toProgressDirection()
progressDirection = attributes.getInteger(
R.styleable.CircularProgressBar_cpb_progress_direction,
progressDirection.value
).toProgressDirection()

// Round Border
roundBorder = attributes.getBoolean(R.styleable.CircularProgressBar_cpb_round_border, roundBorder)
roundBorder =
attributes.getBoolean(R.styleable.CircularProgressBar_cpb_round_border, roundBorder)

// Angle
startAngle = attributes.getFloat(R.styleable.CircularProgressBar_cpb_start_angle, 0f)

// Indeterminate Mode
indeterminateMode = attributes.getBoolean(R.styleable.CircularProgressBar_cpb_indeterminate_mode, indeterminateMode)
indeterminateMode = attributes.getBoolean(
R.styleable.CircularProgressBar_cpb_indeterminate_mode,
indeterminateMode
)

attributes.recycle()
}
Expand All @@ -249,32 +281,48 @@ class CircularProgressBar(context: Context, attrs: AttributeSet? = null) : View(
super.onDraw(canvas)

canvas.drawOval(rectF, backgroundPaint)
val realProgress = (if (indeterminateMode) progressIndeterminateMode else progress) * DEFAULT_MAX_VALUE / progressMax
val realProgress =
(if (indeterminateMode) progressIndeterminateMode else progress) * DEFAULT_MAX_VALUE / progressMax

val isToRightFromIndeterminateMode = indeterminateMode && progressDirectionIndeterminateMode.isToRight()
val isToRightFromIndeterminateMode =
indeterminateMode && progressDirectionIndeterminateMode.isToRight()
val isToRightFromNormalMode = !indeterminateMode && progressDirection.isToRight()
val angle = (if (isToRightFromIndeterminateMode || isToRightFromNormalMode) 360 else -360) * realProgress / 100

canvas.drawArc(rectF, if (indeterminateMode) startAngleIndeterminateMode else startAngle, angle, false, foregroundPaint)
val angle =
(if (isToRightFromIndeterminateMode || isToRightFromNormalMode) 360 else -360) * realProgress / 100

canvas.drawArc(
rectF,
if (indeterminateMode) startAngleIndeterminateMode else startAngle,
angle,
false,
foregroundPaint
)
}

override fun setBackgroundColor(backgroundColor: Int) {
backgroundProgressBarColor = backgroundColor
}

private fun manageColor() {
foregroundPaint.shader = createLinearGradient(progressBarColorStart ?: progressBarColor,
progressBarColorEnd ?: progressBarColor, progressBarColorDirection)
foregroundPaint.shader = createLinearGradient(
progressBarColorStart ?: progressBarColor,
progressBarColorEnd ?: progressBarColor, progressBarColorDirection
)
}

private fun manageBackgroundProgressBarColor() {
backgroundPaint.shader = createLinearGradient(
backgroundProgressBarColorStart ?: backgroundProgressBarColor,
backgroundProgressBarColorEnd ?: backgroundProgressBarColor,
backgroundProgressBarColorDirection)
backgroundProgressBarColorStart ?: backgroundProgressBarColor,
backgroundProgressBarColorEnd ?: backgroundProgressBarColor,
backgroundProgressBarColorDirection
)
}

private fun createLinearGradient(startColor: Int, endColor: Int, gradientDirection: GradientDirection): LinearGradient {
private fun createLinearGradient(
startColor: Int,
endColor: Int,
gradientDirection: GradientDirection,
): LinearGradient {
var x0 = 0f
var y0 = 0f
var x1 = 0f
Expand All @@ -284,8 +332,14 @@ class CircularProgressBar(context: Context, attrs: AttributeSet? = null) : View(
GradientDirection.RIGHT_TO_LEFT -> x0 = width.toFloat()
GradientDirection.TOP_TO_BOTTOM -> y1 = height.toFloat()
GradientDirection.BOTTOM_TO_END -> y0 = height.toFloat()
GradientDirection.CENTER_TO_HORIZONTAL -> x0 = width.toFloat() / 2
GradientDirection.CENTER_TO_VERTICAL -> y0 = height.toFloat() / 2
}
val mode = when (gradientDirection) {
GradientDirection.CENTER_TO_HORIZONTAL, GradientDirection.CENTER_TO_VERTICAL -> Shader.TileMode.MIRROR
else -> Shader.TileMode.CLAMP
}
return LinearGradient(x0, y0, x1, y1, startColor, endColor, Shader.TileMode.CLAMP)
return LinearGradient(x0, y0, x1, y1, startColor, endColor, mode)
}
//endregion

Expand All @@ -295,8 +349,14 @@ class CircularProgressBar(context: Context, attrs: AttributeSet? = null) : View(
val width = getDefaultSize(suggestedMinimumWidth, widthMeasureSpec)
val min = min(width, height)
setMeasuredDimension(min, min)
val highStroke = if (progressBarWidth > backgroundProgressBarWidth) progressBarWidth else backgroundProgressBarWidth
rectF.set(0 + highStroke / 2, 0 + highStroke / 2, min - highStroke / 2, min - highStroke / 2)
val highStroke =
if (progressBarWidth > backgroundProgressBarWidth) progressBarWidth else backgroundProgressBarWidth
rectF.set(
0 + highStroke / 2,
0 + highStroke / 2,
min - highStroke / 2,
min - highStroke / 2
)
}
//endregion

Expand All @@ -309,12 +369,17 @@ class CircularProgressBar(context: Context, attrs: AttributeSet? = null) : View(
* @param startDelay [Long] optional, null by default.
*/
@JvmOverloads
fun setProgressWithAnimation(progress: Float,
duration: Long? = null,
interpolator: TimeInterpolator? = null,
startDelay: Long? = null) {
fun setProgressWithAnimation(
progress: Float,
duration: Long? = null,
interpolator: TimeInterpolator? = null,
startDelay: Long? = null
) {
progressAnimator?.cancel()
progressAnimator = ValueAnimator.ofFloat(if (indeterminateMode) progressIndeterminateMode else this.progress, progress)
progressAnimator = ValueAnimator.ofFloat(
if (indeterminateMode) progressIndeterminateMode else this.progress,
progress
)
duration?.also { progressAnimator?.duration = it }
interpolator?.also { progressAnimator?.interpolator = it }
startDelay?.also { progressAnimator?.startDelay = it }
Expand All @@ -333,31 +398,33 @@ class CircularProgressBar(context: Context, attrs: AttributeSet? = null) : View(

//region Extensions Utils
private fun Float.dpToPx(): Float =
this * Resources.getSystem().displayMetrics.density
this * Resources.getSystem().displayMetrics.density

private fun Float.pxToDp(): Float =
this / Resources.getSystem().displayMetrics.density
this / Resources.getSystem().displayMetrics.density

private fun Int.toProgressDirection(): ProgressDirection =
when (this) {
1 -> ProgressDirection.TO_RIGHT
2 -> ProgressDirection.TO_LEFT
else -> throw IllegalArgumentException("This value is not supported for ProgressDirection: $this")
}
when (this) {
1 -> ProgressDirection.TO_RIGHT
2 -> ProgressDirection.TO_LEFT
else -> throw IllegalArgumentException("This value is not supported for ProgressDirection: $this")
}

private fun ProgressDirection.reverse(): ProgressDirection =
if (this.isToRight()) ProgressDirection.TO_LEFT else ProgressDirection.TO_RIGHT
if (this.isToRight()) ProgressDirection.TO_LEFT else ProgressDirection.TO_RIGHT

private fun ProgressDirection.isToRight(): Boolean = this == ProgressDirection.TO_RIGHT

private fun Int.toGradientDirection(): GradientDirection =
when (this) {
1 -> GradientDirection.LEFT_TO_RIGHT
2 -> GradientDirection.RIGHT_TO_LEFT
3 -> GradientDirection.TOP_TO_BOTTOM
4 -> GradientDirection.BOTTOM_TO_END
else -> throw IllegalArgumentException("This value is not supported for GradientDirection: $this")
}
when (this) {
1 -> GradientDirection.LEFT_TO_RIGHT
2 -> GradientDirection.RIGHT_TO_LEFT
3 -> GradientDirection.TOP_TO_BOTTOM
4 -> GradientDirection.BOTTOM_TO_END
5 -> GradientDirection.CENTER_TO_HORIZONTAL
6 -> GradientDirection.CENTER_TO_VERTICAL
else -> throw IllegalArgumentException("This value is not supported for GradientDirection: $this")
}
//endregion

/**
Expand All @@ -375,7 +442,9 @@ class CircularProgressBar(context: Context, attrs: AttributeSet? = null) : View(
LEFT_TO_RIGHT(1),
RIGHT_TO_LEFT(2),
TOP_TO_BOTTOM(3),
BOTTOM_TO_END(4)
BOTTOM_TO_END(4),
CENTER_TO_HORIZONTAL(5),
CENTER_TO_VERTICAL(6)
}

}
4 changes: 4 additions & 0 deletions circularprogressbar/src/main/res/values/attrs.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
<flag name="right_to_left" value="2" />
<flag name="top_to_bottom" value="3" />
<flag name="bottom_to_top" value="4" />
<flag name="center_to_horizontal" value="5" />
<flag name="center_to_vertical" value="6" />
</attr>
<attr name="cpb_background_progressbar_color" format="color" />
<attr name="cpb_background_progressbar_color_start" format="color" />
Expand All @@ -20,6 +22,8 @@
<flag name="right_to_left" value="2" />
<flag name="top_to_bottom" value="3" />
<flag name="bottom_to_top" value="4" />
<flag name="center_to_horizontal" value="5" />
<flag name="center_to_vertical" value="6" />
</attr>
<attr name="cpb_progressbar_width" format="dimension" />
<attr name="cpb_background_progressbar_width" format="dimension" />
Expand Down
2 changes: 2 additions & 0 deletions gradle/publish-jitpack.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
apply plugin: 'com.github.dcendents.android-maven'
group='com.github.michaellee123'
Loading