四:自定义View,实现水波纹效果(正余弦水波纹)

本文主要参考 Android 自定义view实现水波纹效果

四:自定义View,实现水波纹效果(正余弦水波纹)_第1张图片
GIF.gif

思路基本如下:

1、确定水波函数方程

是一个标准的正余弦函数:**y = Asin(wx+b)+h **,
其中,w影响周期,A影响振幅,h影响y位置,b为初相
周期:(2π-b)/w,

2、根据函数方程得出每一个波纹上点的坐标

一个viewWidth是一个周期
将每个像素点的初始Y值存入sourcePoint

        W= Math.PI*2/ viewWidth
        for (i in 0 until viewWidth){
            sourcePoint[i]=A*Math.sin(W*i) + H
        }

之后,每次刷新的时候,根据offset,将Y值copy到destPoint

    private fun resetDestPoint() {
        val oneYInterval=sourcePoint.size-oneOffset
        System.arraycopy(sourcePoint,oneOffset,destOnePoint,0,oneYInterval)
        System.arraycopy(sourcePoint,0,destOnePoint,oneYInterval,oneOffset)
        val twoYInterval=sourcePoint.size-twoOffset
        System.arraycopy(sourcePoint,twoOffset,destTwoPoint,0,twoYInterval)
        System.arraycopy(sourcePoint,0,destTwoPoint,twoYInterval,twoOffset)
    }
3、绘制

其中波纹上每个点的坐标是(i,destPoint[i])

        for (i in 0 until viewWidth){
            canvas.drawLine(i.toFloat(), viewHeight-destOnePoint[i]!!.toFloat()-40, i.toFloat(),viewHeight-destOnePoint[i]!!.toFloat(),wavePaintOne)
            canvas.drawLine(i.toFloat(), viewHeight-destTwoPoint[i]!!.toFloat()-40, i.toFloat(),viewHeight-destOnePoint[i]!!.toFloat(),wavePaintTwo)
        }
4、水波平移,调用 invalidate()方法,

在每次刷新的时候都有改变offset的值

        oneOffset+=10
        twoOffset+=5

通过他们就可以改变destOnePoint、destTwoPoint的值

代码如下:

class DynamicWave : View {
    constructor(context:Context) : super(context){ initView() }
    constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs){ initView() }
    constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr){ initView() }

    var viewWidth:Int=0
    var viewHeight:Int=0

    var sourcePoint:Array = emptyArray()
    var destOnePoint:Array = emptyArray()
    var destTwoPoint:Array = emptyArray()

    val A:Int=10
    var W:Double=0.0
    val H:Int=40

    var oneOffset=0
    var twoOffset=0

    var wavePaintOne:Paint?=null
    var wavePaintTwo:Paint?=null
    var paintFilter:PaintFlagsDrawFilter?=null

    private fun initView() {
        wavePaintOne= Paint(Paint.ANTI_ALIAS_FLAG)
        wavePaintOne?.apply {
            color=Color.GREEN
            style=Paint.Style.FILL
            alpha=60
        }
        wavePaintTwo= Paint(Paint.ANTI_ALIAS_FLAG)
        wavePaintTwo?.apply {
            color=Color.GRAY
            style=Paint.Style.FILL
            alpha= 60
        }

        paintFilter=PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG or Paint.FILTER_BITMAP_FLAG)
    }

    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        super.onSizeChanged(w, h, oldw, oldh)
        viewWidth=w
        viewHeight=h
        if (viewWidth==0){
            return
        }
        sourcePoint= arrayOfNulls(viewWidth)
        destOnePoint= arrayOfNulls(viewWidth)
        destTwoPoint= arrayOfNulls(viewWidth)
        W= Math.PI*2/ viewWidth
        for (i in 0 until viewWidth){
            sourcePoint[i]=A*Math.sin(W*i) + H
        }
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        canvas.drawFilter=paintFilter
        resetDestPoint()
        for (i in 0 until viewWidth){
            canvas.drawLine(i.toFloat(), viewHeight-destOnePoint[i]!!.toFloat()-40, i.toFloat(),viewHeight-destOnePoint[i]!!.toFloat(),wavePaintOne)
            canvas.drawLine(i.toFloat(), viewHeight-destTwoPoint[i]!!.toFloat()-40, i.toFloat(),viewHeight-destOnePoint[i]!!.toFloat(),wavePaintTwo)
        }
        oneOffset+=10
        twoOffset+=5
        if (oneOffset>=viewWidth){
            oneOffset=0
        }
        if (twoOffset>=viewWidth){
            twoOffset=0
        }
        invalidate()

    }

    private fun resetDestPoint() {

        val oneYInterval=sourcePoint.size-oneOffset
        System.arraycopy(sourcePoint,oneOffset,destOnePoint,0,oneYInterval)
        System.arraycopy(sourcePoint,0,destOnePoint,oneYInterval,oneOffset)

        val twoYInterval=sourcePoint.size-twoOffset
        System.arraycopy(sourcePoint,twoOffset,destTwoPoint,0,twoYInterval)
        System.arraycopy(sourcePoint,0,destTwoPoint,twoYInterval,twoOffset)

    }
}


5、kotlin

emptyArray()
arrayOfNulls(viewWidth)
for (i in 0 until size){}

参考:

https://github.com/fanrunqi/WaveProgressView

你可能感兴趣的:(四:自定义View,实现水波纹效果(正余弦水波纹))