Android MIUI 即刻APP 返回手勢及動畫 探索

swipe_left.jpeg
swipe_right.jpeg

18 年末作 Readhub APP 時就加入了這個返回動畫效果。一直到如今,纔有時間來簡單總結和封裝一下。 git

swipeback.gif

不知道這個返回手勢動畫究竟是 MIUI 仍是「即刻」APP 獨創,由於我那會兒還沒用上 MIUI 全面屏。不過 MIUI 全面屏那個返回手勢相對簡單,固定位置。從這個效果上看,我以爲是 MIUI 先有這個效果,而後 「即刻」APP 優化豐富了一下。固然,可能還有另一種狀況,這是早就有的效果圖,只是在目前,我已知有使用的就上面兩個場景。程序員

總結起來很簡單,就是一個「貝塞爾曲線」的繪製,再外加一個箭頭繪製。箭頭什麼的的繪製在以前的倉庫中已經練習過不少。此次着重說說這個特殊圖形須要怎麼繪製。github

對於貝塞爾曲線繪製,以前玩過兩階、三階的。第一次看到這個效果,以爲貝塞爾曲能實現,可是這是幾階的,高階的怎麼玩,那就是從頭開始。api

在通過一番把玩探索後,最終肯定這就是五階的貝塞爾曲線, Android 彷佛默認沒有高階對應的 api。緩存

draw
那這怎麼辦呢?曲線就是函數嘛,確定有公式,網上就搜到公式寫法。

private fun calculateY(i: Int, j: Int, t: Float): Float {
    return if (i == 1) {
        (1 - t) * controlPoints[j].y + t * controlPoints[j + 1].y
    } else (1 - t) * calculateY(i - 1, j, t) + t * calculateY(i - 1, j + 1, t)
}
複製代碼

controlPoints 對應的就是那個五個控制點的集合。markdown

addControlPoint(0, 0f, yResult - maxPeakValue * 1.5f)
addControlPoint(1, 0f, yResult - maxPeakValue * 1.5f * GOLDEN_RATIO)
addControlPoint(2, min, yResult)
addControlPoint(3, 0f, yResult + maxPeakValue * 1.5f * GOLDEN_RATIO)
addControlPoint(4, 0f, yResult + maxPeakValue * 1.5f)
複製代碼

接着就是控制是否攔截事件,我如今是作成 Helper 這種工具類型,和對應的 ViewGroup 是解耦的,其實就是 ViewDragHelper 的一個簡單實現。函數

對了,最後考慮下來,實現了左右兩邊的滑動效果。至於上下,我以爲這種場景不大,就懶得去作了。工具

具體代碼細節就不貼了,源碼也沒多少,這裏講遇到的一些細節問題或者寫出來的 bugoop

返回退出應用後,後臺程序預覽中存在返回手勢效果

這裏其實就是一個前後問題,一開始是同步執行 invalidate()onBackReleased() 。後來使用 Runnable + postDalay() 來延遲 onBackReleased() 執行。post

貝塞爾曲線貼近屏幕的地方總有一個像素的白線

這裏後面排查出來是我添加控制點,for 循環時角標是[0,length-1],最後一個沒有添加計算到,因此計算出來的控制點就少了一個。最終效果就是繪製出來的圖形 x 軸沒有徹底對稱。誤差就在 1px 左右。 最後的效果就是總感受下方有一跟白線。

for 循環處理好以後,發現右邊繪製出來仍是會有這個狀況,具體緣由不清楚,由於單看數據層面,它確定是貼邊的。最後很討巧,使用到 translate()Canvas 平移一個像素規避掉,這簡直是程序員的小巧思,哈哈 🐶。

控制點數量及緩存

由於是用公式算的控制點,因此每一次繪製,其實簡單理解就是講一個一個點鏈接成一條曲線的。那麼問題就是,點多,曲線固然最逼真,可是單位時間處理的數據量就上去了。 點少,可能你看到就是折線圖了。 最後均衡在 50 個控制點,點與點之間的比例就是 2% 。在繪製等方法中確定不能頻繁建立對象,因此這 50 個點須要複用。

倉庫地址

lovejjfg/SwipeBack 現已同步 jcenter 。 詳情請移步 README.md

相關文章
相關標籤/搜索