美文网首页
四:自定义View,实现水波纹效果(正余弦水波纹)

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

作者: i冰点 | 来源:发表于2017-06-22 18:01 被阅读245次

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

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<Double?> = emptyArray()
    var destOnePoint:Array<Double?> = emptyArray()
    var destTwoPoint:Array<Double?> = 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,实现水波纹效果(正余弦水波纹)

      本文链接:https://www.haomeiwen.com/subject/gvbfcxtx.html