Android 憶童年 DVD機待機 loading 動畫
什麼?你不知道 DVD 是啥?呵呵,暴露年齡了。這是一個具有年代感的東西。你沒看到過說明要麼你年輕,年輕好啊。要麼你家窮,我那會兒反正是租的碟片在同學家放,自己家買是不可能的了,一輩子都不可能。
正式開始實現之前,開始簡單的建模及分析。
整體效果就是:一個圓或者矩形在一個大的矩形(類比電視螢幕)上面運動,撞到螢幕邊緣就開始反彈,這裡類比於光的反射。直到它成功切入一個角落,那麼就停止運動。
轉化一下其實就是我需要在兩點連線的軌跡上面作圓或者其他圖形,這兩點必須滿足在大的矩形的任意兩邊上(可以是相鄰的,也可以是隔開的,單不能是同一邊)。
那麼對應到 Android 中就轉換成兩個問題,第一 如何通過已知點和角度和相關約束條件計算出另外一個點的座標。第二 如何拿到兩點相連的軌跡。
針對問題一,很明確,這裡需要使用到勾股定理那些知識,或者準確的說,這裡就是需要用到「正切函式」。
針對問題二,這裡就需要使用到 Path 和 PathMeasure 這兩個類。在 Path 中我們可以通過 moveTo() lineTo() 兩個方法實現兩點連線。然後呼叫 pathMeasure.setPath(path, false)
方式使 Path 和 PathMeasure 相關聯。接著介紹 PathMeasure 一個超級厲害的方法: pathMeasure.getPosTan(distance, positionArray, tanArray)
tanValue = Math.abs(tanArray[1] / tanArray[0])
兩個大問題解決了,在討論一些小問題,比如說運動軌跡到底有多少種?
大致就是這個情況,唉,第一次用「預覽」畫圖,大家能看明白就好。這裡具體有八種情況的軌跡。按大類分就是四大類,分別對應各個象限的情況。每個象限又有上下兩種運動方向,所以就是有八大類。
軌跡有八種,但是要再具體的話,每一種又可以再拆分出一種情況。那就是上面提到的,這兩點是相鄰的或者是隔開的。
最後直接剛上一組程式碼,對應上圖的相關情況。
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