Skip to content

Instantly share code, notes, and snippets.

@dsantix
Created April 18, 2022 23:44
Show Gist options
  • Save dsantix/cf1bf176661f8a2576794eabed0daf49 to your computer and use it in GitHub Desktop.
Save dsantix/cf1bf176661f8a2576794eabed0daf49 to your computer and use it in GitHub Desktop.
Two Indicators Progress Bar
import android.animation.ObjectAnimator
import android.animation.TimeInterpolator
import android.content.Context
import android.content.res.TypedArray
import android.graphics.*
import android.text.TextPaint
import android.util.AttributeSet
import android.util.TypedValue
import android.view.View
import android.view.ViewOutlineProvider
import androidx.annotation.FloatRange
import androidx.annotation.Keep
import androidx.core.content.res.ResourcesCompat
import androidx.interpolator.view.animation.FastOutSlowInInterpolator
import com.sntsoftwares.esports.R
class TwoIndicatorProgressBar @JvmOverloads constructor(context: Context, attributeSet: AttributeSet? = null, defStyleAttr: Int = 0) : View(context, attributeSet, defStyleAttr) {
private val progressLeftPaint: Paint = Paint()
private val progressRightPaint: Paint = Paint()
private var percentageTextPaint = TextPaint()
private lateinit var containerRectF: RectF
private var currentProgressValue: Float = 0.0f
private var progressPadding = 0f
private var cornersProgressBar : Float = 0f
private var typedArray: TypedArray? = null
private lateinit var indicatorOutlineProvider : ViewOutlineProvider
init {
typedArray = context.theme.obtainStyledAttributes(
attributeSet,
R.styleable.TwoIndicatorProgressBar,
0,
0
)
initAttr()
outlineProvider = indicatorOutlineProvider
clipToOutline = true
}
private fun initAttr() {
indicatorOutlineProvider = object : ViewOutlineProvider(){
override fun getOutline(p0: View?, p1: Outline?) {
val left = 0
val top = 0
val right = p0?.width
val bottom = p0?.height
val cornerRadius = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, cornersProgressBar, resources.displayMetrics)
// all corners
p1?.setRoundRect(left, top, right!!, bottom!!, cornerRadius)
}
}
typedArray?.apply {
currentProgressValue = kotlin.math.abs(getInt(R.styleable.TwoIndicatorProgressBar_bar_percentage, 50))
.coerceIn(0, 100)
.toFloat()
progressRightPaint.color =
getColor(R.styleable.TwoIndicatorProgressBar_bar_progressRightColor, Color.RED)
progressLeftPaint.color =
getColor(R.styleable.TwoIndicatorProgressBar_bar_progressLeftColor, Color.BLACK)
percentageTextPaint.color = getColor(
R.styleable.TwoIndicatorProgressBar_bar_textColor,
Color.WHITE
)
percentageTextPaint.textSize =
getDimensionPixelSize(R.styleable.TwoIndicatorProgressBar_bar_textSize, 32).toFloat()
val fontId = getResourceId(R.styleable.TwoIndicatorProgressBar_android_fontFamily, 0)
if (fontId != 0) {
percentageTextPaint.typeface = ResourcesCompat.getFont(context, fontId)
} else {
percentageTextPaint.typeface = Typeface.create(Typeface.MONOSPACE, Typeface.BOLD)
}
cornersProgressBar = getDimension(R.styleable.TwoIndicatorProgressBar_bar_cornerRadius, 0F)
recycle()
}
}
/***
*
* Set progress without animation
*
*/
@Keep
fun setProgress(@FloatRange(from = 0.0, to = 100.0) progressValue: Float = 10f) {
currentProgressValue = progressValue
invalidate()
}
fun setCornerRadius(radius:Float = 0f) {
cornersProgressBar = radius
invalidate()
}
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
super.onSizeChanged(w, h, oldw, oldh)
containerRectF = RectF()
containerRectF.set(0f, 0f, w.toFloat(), h.toFloat())
}
override fun onDraw(canvas: Canvas?) {
super.onDraw(canvas)
drawProgressBar(canvas)
val textSizeWidth =
percentageTextPaint.measureText("%s%%".format(currentProgressValue.toInt()))
canvas?.drawText(
"%s%%".format(currentProgressValue.toInt()),
containerRectF.left + textSizeWidth / 2,
containerRectF.centerY() + percentageTextPaint.textSize / 2,
percentageTextPaint
)
canvas?.drawText(
"%s%%".format(100 - currentProgressValue.toInt()),
containerRectF.right - textSizeWidth - (textSizeWidth / 2),
containerRectF.centerY() + percentageTextPaint.textSize / 2,
percentageTextPaint
)
}
private fun drawProgressBar(canvas: Canvas?) {
val pathLeft = drawLeftProgress(
containerRectF,
((currentProgressValue / 100.0f) * containerRectF.right),
progressPadding
)
val pathRight = drawRightProgress(
containerRectF,
((currentProgressValue / 100.0f) * containerRectF.right),
progressPadding
)
canvas?.drawPath(pathLeft, progressLeftPaint)
canvas?.drawPath(pathRight, progressRightPaint)
}
private fun drawLeftProgress(
rectF: RectF,
width: Float,
padding: Float
): Path {
val path = Path()
with(rectF) {
path.moveTo(left + padding, padding)
path.lineTo(left + padding, bottom - padding)
path.lineTo(
left + width + (right * 0.00f),
bottom - padding
)
path.lineTo(
left + width - (right * 0.00f) ,
padding
)
}
path.close()
return path
}
private fun drawRightProgress(rectF: RectF, width: Float, padding: Float): Path {
val path = Path()
with(rectF) {
path.moveTo(right - padding, padding)
path.lineTo(right - padding, bottom - padding)
path.lineTo(
left + width + (right * 0.00f),
bottom - padding
)
path.lineTo(
left + width - (right * 0.00f),
padding
)
}
path.close()
return path
}
/***
*
* Set progress value with animation
*
* @param progressValue = Progress value in Float
* @param interpolator = Change the way how values are changing (Default = FastOutSlowInInterpolator)
*
*/
@Keep
fun animateProgress(@FloatRange(from = 0.0, to = 100.0) progressValue: Float = 10f,interpolator: TimeInterpolator = FastOutSlowInInterpolator(), startDelay:Long = 100L, duration: Long = 500L){
val animation = ObjectAnimator.ofFloat(
this,
"progress",
this.currentProgressValue,
progressValue
)
animation.duration = duration
animation.interpolator = interpolator
animation.startDelay = startDelay
animation.start()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment