以前寫過波浪影片,但是如果繪制比較嚴重頻繁會掉幀,后來比較忙也沒去搗騰,現在學習kotlin又把以前的一些知識重新理了一遍
首先對于需要大量繪制的操作,不能直接繪制,可以使用 SurfaceView 來繪制,直接把繪制作業放到子執行緒中去操作,把繪制作業加大一下,你就會發現差距了

思路:
使用的是二級貝塞爾曲線來完成的,簡單的把螢屏對半,然后各用貝塞爾去繪制一個扇形,改變控制點
對比以前:
以前直接draw繪制的,現在借用了SurfaceView,簡化計算邏輯
流程:
1.從繁化簡,首先不考慮其它,波浪形狀是

這個簡單,起點 ,然后螢屏的四分之一就是第二個點,螢屏的二分之一就是第三個點,然后加個二級貝塞爾,扇形就成了
path.reset()
path.moveTo(starPoint[0], starPoint[1])
path.quadTo(quadPoint[0], quadPoint[1], quadPoint[2], quadPoint[3])
canvas.drawPath(path, paint)
2.繪制第二個扇形,同樣的扇形,但是方向反一下,起點就是第一個扇形的最后一個控制點,第二個坐標就是螢屏的四分之三,第三個坐標就是螢屏的寬度,然后連起來就是兩個相連接的扇形,看起來不太像,這里只有線條

path.reset() path.moveTo(starPoint[0], starPoint[1]) path.quadTo(quad1Point[0], quad1Point[1], quad1Point[2], quad1Point[3]) path.quadTo(quad2Point[0], quad2Point[1], quad2Point[2], quad2Point[3]) canvas.drawPath(path, paint)
3.把扇形閉合一下,畫筆設定為填充,這樣看起來有點樣子了,如果能讓這個波浪動起來,基本的效果也就有了,可以改變x坐標移動它們的位置,但是就兩個波浪,移動后很顯然還達不到想要的效果,這時候需要在繪制兩條一模一樣的扇形,然后
回圈切換

paint.style = Paint.Style.FILL //閉合區域 path.lineTo(mWidth, mHeight) path.lineTo(0f, mHeight) path.close()
4.繪制移動的波浪,假設左邊還有一個螢屏,也分為四等分,以此類推,這樣波浪就繪制完成了

5.改變所有波浪的x的坐標,讓它從左往右移動,到臨界點在置為0,重復操作,這里可以交給插值器去做,直接從0開始移動,臨界點是螢屏的寬度,剛好兩個波浪的距離

不用插值器也行,直接自己計算一下,可以看到,動起來了

我這邊為了更好的看到效果,我給每個x坐標控制點都繪制了一個小圓點,這樣看起來就更直觀一點,也有利于除錯一些bug,也可以把坐標都列印出來,方便計算


然后可以看到答應出來的坐標資訊

y坐標基本可以不看,y坐標主要控制扇形的弧度,因為是相反的兩個扇形,所以一個高一個低,然后x坐標根據螢屏的寬度,分了四等份,在用貝塞爾曲線連接起來,這樣一看就清晰多了
因為繪制了圓點,所以看起來視覺上比較生硬,如果把圓點去掉就絲滑多了

這里初步的思路就完成了
class WaterBgSurfaceView(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : SurfaceView(context, attrs, defStyleAttr), SurfaceHolder.Callback { init { init() } constructor(context: Context, attrs: AttributeSet?):this(context, attrs, 0) constructor(context: Context):this(context, null) private lateinit var drawWater: DrawWaterUtils private fun init() { holder.addCallback(this) //透明處理 holder.setFormat(PixelFormat.TRANSPARENT) setZOrderOnTop(true) drawWater = DrawWaterUtils(holder) } @SuppressLint("DrawAllocation") override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) { super.onLayout(changed, left, top, right, bottom) if (changed){ drawWater.init(width,height) } } override fun onDraw(canvas: Canvas?) { super.onDraw(canvas) } override fun surfaceCreated(p0: SurfaceHolder) { drawWater.runDraw() } override fun surfaceChanged(p0: SurfaceHolder, p1: Int, p2: Int, p3: Int) { } override fun surfaceDestroyed(p0: SurfaceHolder) { drawWater.stopDraw() } }View Code
class DrawWaterUtils(private val holder: SurfaceHolder) : Thread() { private var mWidth: Float = 0f private var mHeight: Float = 0f //波浪的高度 private var mWaterHeight: Float = 0f //起伏的高度 private var mWaterUp: Float = 0f /** * off = 偏移值 */ private var offx:Float = 0f private var path: Path = Path() private var paint: Paint = Paint() private var isRun: Boolean = false private var circlePaint: Paint = Paint() private lateinit var mValueAnimator: ValueAnimator init { // 去除畫筆鋸齒 paint.isAntiAlias = true // 設定風格為實線 paint.style = Paint.Style.FILL paint.strokeWidth = 2f circlePaint.style = Paint.Style.FILL } fun init(width: Int, height: Int){ mWidth = width.toFloat() mHeight = height.toFloat() //線性差值器 mValueAnimator = ValueAnimator.ofFloat(0f, mWidth) mValueAnimator.duration = 1700 mValueAnimator.interpolator = LinearInterpolator() mValueAnimator.repeatCount = ValueAnimator.INFINITE mValueAnimator.addUpdateListener { animation -> offx = animation.animatedValue as Float } //波浪的高度 mWaterHeight = mHeight / 2 //起伏的高度 mWaterUp = mWaterHeight / 2 } fun runDraw(){ isRun = true start() mValueAnimator.start() } fun stopDraw(){ isRun = false mValueAnimator.cancel() } override fun run() { var canvas: Canvas? while (isRun){ canvas = holder.lockCanvas() synchronized(holder) { if (canvas != null) { //清除畫布 canvas.drawColor( KtxProvider.mContext.getColor(R.color.text_color_titleBar_title), android.graphics.PorterDuff.Mode.CLEAR ) paint.color = KtxProvider.mContext.getColor(R.color.bg_color_3159c7_83) circlePaint.color = KtxProvider.mContext.getColor(R.color.black) water(canvas) //回圈起伏 // offx += 3 // if (offx >= mWidth) { // offx = 0f // } // 解除鎖定,并提交修改內容 holder.unlockCanvasAndPost(canvas) } } } } private fun water(canvas: Canvas){ path.reset() //起點 path.moveTo(-mWidth + offx, mWaterHeight) //波浪的數量 for (i in 0 until 2) { path.quadTo( -mWidth * 3 / 4 + i * mWidth + offx, mWaterHeight - mWaterUp, -mWidth / 2 + i * mWidth + offx, mWaterHeight ) //canvas.drawCircle(-mWidth * 3 / 4 + i * mWidth + offx, mWaterHeight - mWaterUp,5f,circlePaint) //canvas.drawCircle(-mWidth / 2 + i * mWidth + offx, mWaterHeight,5f,circlePaint) path.quadTo( -mWidth / 4 + i * mWidth + offx, mWaterHeight + mWaterUp, i * mWidth + offx, mWaterHeight ) //canvas.drawCircle(-mWidth / 4 + i * mWidth + offx, mWaterHeight + mWaterUp,5f,circlePaint) //canvas.drawCircle(i * mWidth + offx, mWaterHeight,5f,circlePaint) Log.e( "===\n", "i = $i\n" + "x1 ${-mWidth * 3 / 4 + i * mWidth} y1 ${mWaterHeight - mWaterUp} x2 ${-mWidth / 2 + i * mWidth} y2 $mWaterHeight \n" + "x1 ${-mWidth / 4 + i * mWidth} y1 ${mWaterHeight + mWaterUp} x2 ${i * mWidth} y2 $mWaterHeight" ) } //閉合操作 path.lineTo(mWidth, mHeight) path.lineTo(0f, mHeight) path.close() canvas.drawPath(path, paint) } }View Code
github:https://github.com/1024477951/KotlinStrong
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/257706.html
標籤:其他
上一篇:kotlin-波浪影片
