Drawable涟漪效果

93 阅读2分钟
class RippleDrawable : Drawable() {

    private val interpolator: Interpolator = AccelerateInterpolator()

    private var mPaint: Paint = Paint()

    private var mRadius: Float = 0.0f

    private var mWidth: Float = 0.0f

    private var mHeight: Float = 0.0f

    private var mMaxRadius: Float = 0.0f

    /**
     * 点击的锚点 x值
     */
    private var mPivotX: Float = 0.0f

    /**
     * 点击的锚点 y值
     */
    private var mPivotY: Float = 0.0f

    private var mMotionX: Float = 0.0f

    private var mMotionY: Float = 0.0f

    private var mProgress = 0.0f

    private var mAlpha = 255

    /**
     * 多久执行runable一次 也就是多久刷新一次
     */

    private var delayTime: Long = 2L

    /**
     * 递减透明度值
     */

    private var desAlpha = 2

    init {
        mPaint.isAntiAlias = true

        mPaint.isDither = true

        mPaint.color = Color.CYAN

        mPaint.style = Paint.Style.FILL
    }

    //绘制圆形
    override fun draw(canvas: Canvas) {
        canvas.drawCircle(mPivotX, mPivotY, mRadius, mPaint)
    }

    override fun onBoundsChange(bounds: Rect) {
        super.onBoundsChange(bounds)
        mWidth = bounds.width().toFloat()
        mHeight = bounds.height().toFloat()
        mMaxRadius = min(mWidth, mHeight)
    }

    override fun setAlpha(alpha: Int) {
        mPaint.alpha = alpha
    }

    override fun setColorFilter(colorFilter: ColorFilter?) {
        mPaint.colorFilter = colorFilter
    }

    override fun getOpacity(): Int {
        return PixelFormat.OPAQUE;
    }

    fun onTouchEvent(event: MotionEvent) {
        when (event.actionMasked) {
            MotionEvent.ACTION_DOWN -> {
                onTouchDown(event)
            }

            MotionEvent.ACTION_MOVE -> {
                onTouchMove(event)
            }

            MotionEvent.ACTION_UP -> {
                onTouchUp(event)
            }
        }
    }

    private fun onTouchUp(event: MotionEvent) {

    }

    private fun onTouchMove(event: MotionEvent) {

    }

    private fun onTouchDown(event: MotionEvent) {
        mMotionX = event.x
        mMotionY = event.y
        mRadius = 0f
        mProgress = 0.0f
        mAlpha = 255
        alpha = mAlpha
        unscheduleSelf(mEnterRunnable)
        scheduleSelf(mEnterRunnable, SystemClock.uptimeMillis() + delayTime)
    }

    private val mExitRunnable: Runnable = object : Runnable {
        override fun run() {
            val alpha = mAlpha - desAlpha
            if (alpha > 0) {
                //从不透明变成完全透明实现Drawable内容不可见
                mAlpha = alpha
                setAlpha(alpha)
                invalidateSelf()
                scheduleSelf(this, SystemClock.uptimeMillis() + delayTime)
            } else {
                mAlpha = 0
                setAlpha(mAlpha)
                invalidateSelf()
            }
        }
    }

    private val mEnterRunnable: Runnable = object : Runnable {
        override fun run() {
            //进度大于等于1了,那么就执行退出动画
            if (mProgress >= 1.0f) {
                unscheduleSelf(this)
                scheduleSelf(mExitRunnable, SystemClock.uptimeMillis() + delayTime)
            }
            //不断增大圆形半径
            mProgress += 0.02f
            mRadius = mMaxRadius * interpolator.getInterpolation(mProgress)
            mPivotX = mMotionX
            mPivotY = mMotionY
            invalidateSelf()
            scheduleSelf(this, SystemClock.uptimeMillis() + delayTime)
        }
    }


}

包含了涟漪效果Drawable的Button。

class RippleButton @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : AppCompatButton(context, attrs, defStyleAttr), Drawable.Callback {
    private val mDrawable: RippleDrawable = RippleDrawable()

    init {
        mDrawable.callback = this
    }

    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        super.onSizeChanged(w, h, oldw, oldh)
        mDrawable.setBounds(0, 0, width, height)
    }

    override fun onDraw(canvas: Canvas) {
        mDrawable.draw(canvas)
        super.onDraw(canvas)
    }

    override fun verifyDrawable(who: Drawable): Boolean {
        return mDrawable == who || super.verifyDrawable(who)
    }

    override fun onTouchEvent(event: MotionEvent): Boolean {
        mDrawable.onTouchEvent(event)
        super.onTouchEvent(event)
        return true
    }
}

RippleDrawable内部onBoundsChange会在View的onSizeChange发生回调,会记录当前Drawable展示的宽高和圆形的最大半径,在draw方法中会根据圆心和半径绘制圆形,内部的mEnterRunnable表示用户按下时执行的圆形不断变大动画,mExitRunnable表示变大动画执行完成后圆形从不透明到全透明最后消失的动画。

效果视频上传不了,可以跑代码看下效果。