Skip to content

Instantly share code, notes, and snippets.

@AndrewKhaynus
Created March 4, 2020 12:46
Show Gist options
  • Star 9 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save AndrewKhaynus/0cca8abf7b4035849046de03fca31367 to your computer and use it in GitHub Desktop.
Save AndrewKhaynus/0cca8abf7b4035849046de03fca31367 to your computer and use it in GitHub Desktop.
import android.animation.TimeInterpolator
import android.content.Context
import android.graphics.*
import android.util.AttributeSet
import android.view.View
import android.graphics.Shader
import android.animation.ValueAnimator
import android.view.animation.LinearInterpolator
import androidx.annotation.ColorInt
class GradientProgressBar @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0)
: View(context, attrs, defStyleAttr) {
@ColorInt private val yellow = -0x006300
@ColorInt private val orange = -0x0021E9
@ColorInt private val grey = -0x8F8F8F
private val rotationAngle = 30f
private val speedMultiplier = 1.2
private val gradientLength = 150f
private val animationDuration = 500L
private val backgroundRect = RectF()
private val progressRect = RectF()
private var parentWidth = 0f
private var parentHeight = 0f
private var matrixTransitionOffset = 0f
set(value) {
field = value
postInvalidateOnAnimation()
}
private var transitionAnimator: ValueAnimator? = null
private var progressAnimator: ValueAnimator? = null
private val paint = Paint()
private val progressPaint = Paint()
private val shader = createShader()
private val transformMatrix = Matrix()
private var percentProgress = 0f
set(value) {
field = value
invalidate()
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
parentWidth = MeasureSpec.getSize(widthMeasureSpec).toFloat()
parentHeight = MeasureSpec.getSize(heightMeasureSpec).toFloat()
progressPaint.isAntiAlias = true
progressPaint.style = Paint.Style.FILL
paint.style = Paint.Style.FILL
paint.isAntiAlias = true
backgroundRect.set(0f, 0f, parentWidth, parentHeight)
}
override fun onDraw(canvas: Canvas?) {
super.onDraw(canvas)
paint.color = grey
canvas?.drawRoundRect(backgroundRect, parentHeight/2, parentHeight/2, paint)
transformMatrix.setTranslate(matrixTransitionOffset, 0f)
transformMatrix.postRotate(rotationAngle)
shader.setLocalMatrix(transformMatrix)
progressPaint.shader = shader
progressRect.set(0f, 0f, (parentWidth/100) * percentProgress, parentHeight)
canvas?.drawRoundRect(progressRect, parentHeight/2, parentHeight/2, progressPaint)
}
private fun createShader(): Shader {
return LinearGradient(0f, 0f, gradientLength, parentHeight, yellow, orange, Shader.TileMode.REPEAT)
}
override fun onAttachedToWindow() {
super.onAttachedToWindow()
transitionAnimator = ValueAnimator.ofFloat(0f, gradientLength).apply {
addUpdateListener { matrixTransitionOffset = it.animatedValue as Float }
duration = (animationDuration * speedMultiplier).toLong()
repeatMode = ValueAnimator.RESTART
repeatCount = ValueAnimator.INFINITE
interpolator = LinearInterpolator()
start()
}
}
override fun onDetachedFromWindow() {
transitionAnimator?.cancel()
progressAnimator?.cancel()
super.onDetachedFromWindow()
}
fun setProgress(progress: Float,
duration: Long = animationDuration,
interpolator: TimeInterpolator = LinearInterpolator()) {
progressAnimator?.end()
progressAnimator = ValueAnimator.ofFloat(percentProgress, progress).apply {
addUpdateListener { percentProgress = it.animatedValue as Float }
this.duration = duration
this.interpolator = interpolator
start()
}
}
fun getProgress(): Float {
return percentProgress
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment