Android kotlin实现自定义水波纹效果

Android kotlin实现自定义水波纹效果

最近做项目需要用kotlin实现一个水波纹效果,所以自己写了一个,怕以后忘记所以上来总结和分享一下,希望对大家也有帮助!不说废话了,直接上代码,在代码里面都加了注释,相信大家一看就懂了!下面是水波纹自定义view的全部代码:

class WaterRipplesView(context: Context, attrs: AttributeSet) : View(context, attrs) {

    /**
     * 默认的周期
     */
    private var mCycleFactorW = 0f

    /**
     * 周期倍数
     */
    private var mCycleMultiple = 1f

    /**
     * 控件总宽度,dp,转化为dp为了减少资源消耗
     */
    private var mTotalWidth = 0
    /**
     * 控件总高度,像素点
     */
    private var mTotalHeight = 0f
    /**
     * 用于保存初始时波纹的Y值
     */
    private lateinit var mYPositions: FloatArray

    /**
     * 保存移动波纹的Y值
     */
    private var mResetYPositions: ArrayList<FloatArray> = ArrayList()
    /**
     * 波纹移动速度
     */
    private var mXOffsetSpeeds: ArrayList<Int> = ArrayList()
    /**
     * 波纹移动距离
     */
    private var mXOffsets: ArrayList<Int> = ArrayList()
    /**
     * 波纹的振幅,默认20
     */
    private var mAmplitude = 30f
    /**
     * 波纹数量,默认3
     */
    private var mRippleNum = 3
    /**
     * 波纹的基础速度
     */
    private var mRippleBaseSpeed = 5f
    /**
     * 波纹的间隔速度
     */
    private var mRippleInterval = 2f

    private var mRippleYPosition = 0.5f

    /**
     * 当前水波纹的y值占比
     */
    private var mCurrentRippleYPosition = 0.5f

    /**
     * 是否要刷新水波纹
     */
    private var mIsStartRefresh = true

    private var paintColor: IntArray

    private var callback: OnPercentageCallback? = null

    private var time = 20L


    private val runnable: Runnable = Runnable {
        postInvalidate()
    }

    companion object {
        private val OFFSET_Y = 0

        private val GREEN_COLOR = intArrayOf(0x6685f53f, 0x8085f53f.toInt(), 0xcc85f53f.toInt())

        private val YELLOW_COLOR = intArrayOf(0x66ffee59, 0x80ffee59.toInt(), 0xccffee59.toInt())

        private val RED_COLOR = intArrayOf(0x66d94a35, 0x80d94a35.toInt(), 0xccd94a35.toInt())
    }

    /**
     * 水波纹画笔
     */
    private val mWavePaint: Paint
    private val mDrawFilter: DrawFilter

    init {
        val ta: TypedArray = context.obtainStyledAttributes(attrs, R.styleable.app_WaterRipplesView)
        mAmplitude = ScreenUtils.dip2px(context, ta.getFloat(R.styleable.app_WaterRipplesView_app_ripple_amplitude, 20f))
        mCycleMultiple = ta.getFloat(R.styleable.app_WaterRipplesView_app_ripple_cycle, 1f)
        mRippleYPosition = ta.getFloat(R.styleable.app_WaterRipplesView_app_ripple_position, 0f)
        mCurrentRippleYPosition = mRippleYPosition
        for (i in 0..mRippleNum - 1) {
            mXOffsetSpeeds.add((mRippleBaseSpeed + i * mRippleInterval).toInt())
            mXOffsets.add(0)
        }

        // 初始绘制波纹的画笔
        mWavePaint = Paint()
        // 去除画笔锯齿
        mWavePaint.isAntiAlias = true
        mWavePaint.strokeWidth = ScreenUtils.dip2px(context, 1f)
        // 设置风格为实线
        mWavePaint.style = Style.FILL
        mDrawFilter = PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG or Paint.FILTER_BITMAP_FLAG)
        paintColor = GREEN_COLOR
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        // 从canvas层面去除绘制时锯齿
        canvas.drawFilter = mDrawFilter
        //水波纹的y值小于当前值时的处理
        if (mCurrentRippleYPosition > mRippleYPosition) {
            mRippleYPosition += 0.02f
            //防止不被2整除的时候出现的问题
            if (mRippleYPosition > mCurrentRippleYPosition) {
                mRippleYPosition = mCurrentRippleYPosition
            }
            //判断波纹的颜色
            if (mRippleYPosition <= 0.5f) {
                paintColor = GREEN_COLOR
            } else if (mRippleYPosition <= 0.75) {
                paintColor = YELLOW_COLOR
            } else {
                paintColor = RED_COLOR
            }
            //回调当前水波纹y轴的占比,用于界面动态显示
            callback!!.onPercentage(mRippleYPosition)
        }
        val startY = mTotalHeight - mRippleYPosition * mTotalHeight + mAmplitude
        // 绘制水波纹
        for (j in 0..mRippleNum - 1) {
            // 使用System.arraycopy方式重新填充第一条波纹的数据
            System.arraycopy(mYPositions, mXOffsets[j], mResetYPositions[j], 0, mYPositions.size - mXOffsets[j])
            System.arraycopy(mYPositions, 0, mResetYPositions[j], mYPositions.size - mXOffsets[j], mXOffsets[j])
            mWavePaint.color = paintColor[j]
            for (i in 0..mTotalWidth - 1) {
                val X = ScreenUtils.dip2px(context, i.toFloat())
                canvas.drawLine(X, startY - mResetYPositions[j][i], X, mTotalHeight, mWavePaint)
            }
        }
        // 改变波纹的移动点
        for (i in 0..mRippleNum - 1) {
            mXOffsets[i] += mXOffsetSpeeds[i]
            // 如果已经移动到结尾处,则重头记录
            if (mXOffsets[i] >= mTotalWidth)
                mXOffsets[i] = 0
        }

        // 延时后刷新水波纹,如果想水波纹更加的流畅,可以不延时,但是会消耗更多的资源
        if (mIsStartRefresh) {
            handler.removeCallbacks(runnable)
            handler.postDelayed(runnable, time)
        }
    }

    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        super.onSizeChanged(w, h, oldw, oldh)
        // 记录下view的宽高
        mTotalWidth = ScreenUtils.px2dip(context, w.toFloat()).toInt()
        mTotalHeight = h.toFloat()

        // 用于保存原始波纹的y值
        mYPositions = FloatArray(mTotalWidth)

        for (i in 0..mRippleNum - 1) {
            mResetYPositions.add(kotlin.FloatArray(mTotalWidth))
        }
        // 将周期定为view总宽度
        mCycleFactorW = (2 * Math.PI / mTotalWidth).toFloat()
        setYPositions()
        //保持时间一直,从而保持不同手机的水波纹移动速度基本一样
        time = (100 * (185f / mTotalWidth)).toLong()
    }

    private fun setYPositions() {
        // 根据view总宽度得出所有对应的y值
        for (i in 0..mTotalWidth - 1) {
            mYPositions[i] = (mAmplitude * Math.sin((mCycleMultiple * mCycleFactorW * i).toDouble()) + OFFSET_Y).toFloat()
        }
    }

    /**
     * 设置波纹占整个控件的多少
     * @param position 值为0到1,该值小于0和大于1时无效
     */
    fun setRipplePosition(position: Float) {
        if (position in 0.0..1.0) {
            mRippleYPosition = 0f
            mCurrentRippleYPosition = position
        }
    }

    /**
     * 设置百分比的监听
     */
    fun setOnPercentageCallback(callback: OnPercentageCallback) {
        this.callback = callback
    }

    /**
     * 开始刷新水波纹
     */
    fun startRefreshRipple() {
        mIsStartRefresh = true
        postInvalidate()
    }

    /**
     * 停止刷新水波纹
     */
    fun stopRefreshRipple() {
        mIsStartRefresh = false
    }

    interface OnPercentageCallback {
        fun onPercentage(percentage: Float)
    }
}

以上就是自定义水波纹的代码了,有不懂的地方欢迎留言,有时间肯定及时回复,还有可以优化的地方欢迎大家一起讨论!

下面是我自己写的demo,需要的可以去下载: 源码下载地址

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值