-
-
Save programmerr47/a685c88f49392715f5e4535828fba8e0 to your computer and use it in GitHub Desktop.
With interpolators
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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