aboutsummaryrefslogtreecommitdiff
path: root/app/src/main/kotlin/com/pitchedapps/frost/views/RippleCanvas.kt
blob: 719a01cc0b9bc71eb05fdbe9e8f446cf6dde07d1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
package com.pitchedapps.frost.views

import android.animation.ValueAnimator
import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.util.AttributeSet
import android.view.View

/**
 * Created by Allan Wang on 2016-11-17.
 *
 *
 * Canvas drawn ripples that keep the previous color
 * Extends to view dimensions
 * Supports multiple ripples from varying locations
 */
class RippleCanvas @JvmOverloads constructor(
        context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {
    val paint: Paint = Paint()
    var baseColor = Color.TRANSPARENT
    val ripples: MutableList<Ripple> = mutableListOf()

    init {
        paint.isAntiAlias = true
        paint.style = Paint.Style.FILL
    }

    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
            }
        }
    }

    @JvmOverloads fun ripple(color: Int, startX: Float = 0f, startY: Float = 0f, duration: Int = 1000) {
        var x = startX
        var y = startY
        val w = width.toFloat()
        val h = height.toFloat()
        if (x == MIDDLE)
            x = w / 2
        else if (x > w) x = 0f
        if (y == MIDDLE)
            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)
        ripples.add(ripple)
        val animator = ValueAnimator.ofFloat(0f, maxRadius)
        animator.duration = duration.toLong()
        animator.addUpdateListener { animation ->
            ripple.setRadius(animation.animatedValue as Float)
            invalidate()
        }
        animator.start()
    }

    fun set(color: Int) {
        baseColor = color
        ripples.clear()
        invalidate()
    }

    inner class Ripple internal constructor(val color: Int, val x: Float, val y: Float, var radius: Float, val maxRadius: Float) {
        internal fun setRadius(r: Float) {
            radius = r
        }
    }

    companion object {
        val MIDDLE = -1.0f
    }
}