diff options
Diffstat (limited to 'library/src/main/kotlin/ca/allanwang/kau/views/RippleCanvas.kt')
-rw-r--r-- | library/src/main/kotlin/ca/allanwang/kau/views/RippleCanvas.kt | 59 |
1 files changed, 47 insertions, 12 deletions
diff --git a/library/src/main/kotlin/ca/allanwang/kau/views/RippleCanvas.kt b/library/src/main/kotlin/ca/allanwang/kau/views/RippleCanvas.kt index 2c44197..9444ef9 100644 --- a/library/src/main/kotlin/ca/allanwang/kau/views/RippleCanvas.kt +++ b/library/src/main/kotlin/ca/allanwang/kau/views/RippleCanvas.kt @@ -7,6 +7,7 @@ import android.graphics.Color import android.graphics.Paint import android.util.AttributeSet import android.view.View +import ca.allanwang.kau.utils.adjustAlpha /** * Created by Allan Wang on 2016-11-17. @@ -28,21 +29,49 @@ class RippleCanvas @JvmOverloads constructor( paint.style = Paint.Style.FILL } + /** + * Drawing the ripples involves having access to the next layer if it exists, + * and using its values to decide on the current color. + * If the next layer requests a fade, we will adjust the alpha of our current layer before drawing. + * Otherwise we will just draw the color as intended + */ override fun onDraw(canvas: Canvas) { - canvas.drawColor(baseColor) - val itr = ripples.iterator() - while (itr.hasNext()) { - val r = itr.next() - paint.color = r.color - canvas.drawCircle(r.x, r.y, r.radius, paint) - if (r.radius == r.maxRadius) { - itr.remove() - baseColor = r.color + val itr = ripples.listIterator() + if (!itr.hasNext()) return canvas.drawColor(baseColor) + var next = itr.next() + canvas.drawColor(colorToDraw(baseColor, next.fade, next.radius, next.maxRadius)) + var last = false + while (!last) { + val current = next + if (itr.hasNext()) next = itr.next() + else last = true + //We may fade any layer except for the last one + paint.color = colorToDraw(current.color, next.fade && !last, next.radius, next.maxRadius) + canvas.drawCircle(current.x, current.y, current.radius, paint) + if (current.radius == current.maxRadius) { + if (!last) { + itr.previous() + itr.remove() + itr.next() + } else { + itr.remove() + } + baseColor = current.color } } } - fun ripple(color: Int, startX: Float = 0f, startY: Float = 0f, duration: Int = 1000) { + /** + * Given our current color and next layer's radius & max, + * we will decide on the alpha of our current layer + */ + internal fun colorToDraw(color: Int, fade: Boolean, current: Float, goal: Float): Int { + if (!fade || (current / goal <= FADE_PIVOT)) return color + val factor = (goal - current) / (goal - FADE_PIVOT * goal) + return color.adjustAlpha(factor) + } + + fun ripple(color: Int, startX: Float = 0f, startY: Float = 0f, duration: Int = 1000, fade: Boolean = Color.alpha(color) != 255) { var x = startX var y = startY val w = width.toFloat() @@ -54,7 +83,7 @@ class RippleCanvas @JvmOverloads constructor( y = h / 2 else if (y > h) y = 0f val maxRadius = Math.hypot(Math.max(x, w - x).toDouble(), Math.max(y, h - y).toDouble()).toFloat() - val ripple = Ripple(color, x, y, 0f, maxRadius) + val ripple = Ripple(color, x, y, 0f, maxRadius, fade) ripples.add(ripple) val animator = ValueAnimator.ofFloat(0f, maxRadius) animator.duration = duration.toLong() @@ -71,9 +100,15 @@ class RippleCanvas @JvmOverloads constructor( invalidate() } - internal class Ripple(val color: Int, val x: Float, val y: Float, var radius: Float, val maxRadius: Float) + internal class Ripple(val color: Int, + val x: Float, + val y: Float, + var radius: Float, + val maxRadius: Float, + val fade: Boolean) companion object { const val MIDDLE = -1.0f + const val FADE_PIVOT = 0.5f } } |