Android 憶童年 DVD 待機動畫

週末逛「即刻」開到這個消息,而後心生一計,我能夠本身作一個 DVD 的 loading效果啊。

什麼?你不知道 DVD 是啥?呵呵,暴露年齡了。這是一個具備年代感的東西。你沒看到過說明要麼你年輕,年輕好啊。要麼你家窮,我那會兒反正是租的碟片在同窗家放,本身家買是不可能的了,一生都不可能。git

正式開始實現以前,開始簡單的建模及分析。github

總體效果就是:一個圓或者矩形在一個大的矩形(類比電視屏幕)上面運動,撞到屏幕邊緣就開始反彈,這裏類比於光的反射。直到它成功切入一個角落,那麼就中止運動。數組

轉化一下其實就是我須要在兩點連線的軌跡上面做圓或者其餘圖形,這兩點必須知足在大的矩形的任意兩邊上(能夠是相鄰的,也能夠是隔開的,單不能是同一邊)。函數

那麼對應到 Android 中就轉換成兩個問題,第一 如何經過已知點和角度和相關約束條件計算出另一個點的座標。第二 如何拿到兩點相連的軌跡。spa

針對問題一,很明確,這裏須要使用到勾股定理那些知識,或者準確的說,這裏就是須要用到「正切函數」。code

針對問題二,這裏就須要使用到 Path 和 PathMeasure 這兩個類。在 Path 中咱們能夠經過 moveTo() lineTo() 兩個方法實現兩點連線。而後調用 pathMeasure.setPath(path, false) 方式使 Path 和 PathMeasure 相關聯。接着介紹 PathMeasure 一個超級厲害的方法: pathMeasure.getPosTan(distance, positionArray, tanArray) 這個方法第一個參數指定一段長度,接着傳入兩個數組,positionArray[2] 和 tanArray[2] 。 最後positionArray 返回的就是對應 distance 後的終點座標,到這裏,終點座標問題解決。更厲害的是後面,給到你 X 和 Y 對應的正切值。那麼咱們這裏須要使用的正切值就是 tanValue = Math.abs(tanArray[1] / tanArray[0])orm

兩個大問題解決了,在討論一些小問題,好比說運動軌跡到底有多少種? cdn

大體就是這個狀況,唉,第一次用「預覽」畫圖,你們能看明白就好。這裏具體有八種狀況的軌跡。按大類分就是四大類,分別對應各個象限的狀況。每一個象限又有上下兩種運動方向,因此就是有八大類。blog

軌跡有八種,可是要再具體的話,每一種又能夠再拆分出一種狀況。那就是上面提到的,這兩點是相鄰的或者是隔開的。get

最後直接剛上一組代碼,對應上圖的相關狀況。

private fun handUp() {
    if (currentX == startX()) {// normal
        val resultX = startX() + (currentY - startY()) / tanValue
        val dx = resultX - endX()
        if (resultX > endX()) {
            Log.e("calculate", "上升 handUp:越界狀況")
            val dy = tanValue * (endX() - currentX)
            path.lineTo(endX(), currentY - dy)
        } else {
            Log.e("calculate", "上升 handUp:正常狀況")
            path.lineTo(resultX, startY())
        }
        needRevert = dx > 0
    } else if (currentX == endX()) {// normal revert
        val resultX = (endY() - currentY) / tanValue
        val dx = resultX - currentX
        if (currentX - resultX < startX()) {
            Log.e("calculate", " handUp 降低:越界狀況")
            path.lineTo(startX(), rectF.height() - dx * tanValue)
            needRevert = true
        } else {
            Log.e("calculate", " handUp 降低:正常狀況")
            path.lineTo(currentX - resultX, rectF.height() - ovalY())
            needRevert = false
        }
    } else {
        Log.e(
            "calculate",
            " handUp 異常狀況:currentX =$currentX startX=${startX()} endx:${endX()} startX=${startX()} endx:${endX()}"
        )
        animator.cancel()
        state = STATE_ERROR
    }
}
複製代碼

最後效果就是這樣的,目前支持「圓形」和「橢圓形」

源碼地址:DVD loading by Joe

相關文章
相關標籤/搜索