Skip to content

Instantly share code, notes, and snippets.

@programmerr47
Created March 28, 2020 14:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save programmerr47/a685c88f49392715f5e4535828fba8e0 to your computer and use it in GitHub Desktop.
Save programmerr47/a685c88f49392715f5e4535828fba8e0 to your computer and use it in GitHub Desktop.
With interpolators
class SonarDrawable(
scalesInter: Interpolator,
alphasInter: Interpolator,
@ColorInt private val tint: Int
) : Drawable() {
private val ripples: Array<Ripple>
private val progressStep: Float
private val animator = ValueAnimator.ofFloat(0f, 1f).apply {
duration = SONAR_DURATION
repeatCount = ValueAnimator.INFINITE
interpolator = LinearInterpolator()
}
init {
ripples = Array(CIRCLE_COUNT) {
Ripple(scalesInter, alphasInter, tint) { bounds }
}
progressStep = 1f / ripples.size
animator.addUpdateListener {
var progressOffset = it.animatedFraction
repeat(ripples.size) {
progressOffset = (progressOffset + progressStep).let { result ->
if (result >= 1f) result - 1f else result
}
ripples[it].progress = progressOffset
}
invalidateSelf()
}
}
override fun draw(canvas: Canvas) {
ripples.forEach { it.draw(canvas) }
}
override fun setAlpha(alpha: Int) {/*ignore*/}
override fun getOpacity(): Int = PixelFormat.OPAQUE
override fun setColorFilter(colorFilter: ColorFilter?) {/*ignore*/}
override fun setVisible(visible: Boolean, restart: Boolean): Boolean {
return super.setVisible(visible, restart).also { changed ->
if (changed) {
with(animator) { if (visible) start() else cancel() }
}
}
}
class Ripple(
private val scalesInter: Interpolator,
private val alphasInter: Interpolator,
private val tint: Int,
private val dBounds: () -> Rect
) {
private val rect: RectF = RectF()
private val paint: Paint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
color = tint
}
@FloatRange(from = .0, to = 1.0, toInclusive = false)
var progress: Float = 0f
set(value) {
field = value
val scaleVal = scalesInter.getInterpolation(value)
val xRadius = scaleVal * dBounds().width() / 2f
val yRadius = scaleVal * dBounds().height() / 2f
rect.left = dBounds().exactCenterX() - xRadius
rect.top = dBounds().exactCenterY() - yRadius
rect.right = dBounds().exactCenterX() + xRadius
rect.bottom = dBounds().exactCenterY() + yRadius
paint.color = tint.applyAlpha((OPAQUE_ALPHA * (1 - alphasInter.getInterpolation(value))).toInt())
}
fun draw(canvas: Canvas) = canvas.drawCircle(rect, paint)
private fun Int.applyAlpha(alpha: Int) =
Color.argb(alpha, Color.red(this), Color.green(this), Color.blue(this))
}
private companion object {
const val SONAR_DURATION = 3000L
const val OPAQUE_ALPHA = 0xFF
const val CIRCLE_COUNT = 4
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment