OneClock的翻頁時鐘效果是如何實現的

xDEHANG發表於2019-03-02

OneSwift - iOS Tips Based On Swift

image

OneClock目前的三個錶盤中使用者最喜歡的是翻頁時鐘。翻頁效果是錶盤的核心,也是我花時間除錯最久的細節。經過7次的產品迭代,終於調整到了一個合適的效果。

image

實現這個動效的方法只需用到 CABasicAnimation中的以X軸旋轉即可。CABasicAnimation實際上還有很多引數,比如大小、透明度、背景顏色等,用這個方法做很多動畫都是可以實現的。

製作翻頁時鐘的效果,實際上需要解決3個問題:

1.只要時間刻度變動就提前翻頁;

2.真實演示出翻頁過程的遮蓋和層級效果;

3.正確顯示數字;

實現過程

將翻頁的過程通過側面角度,解析成下圖中所示的樣子。翻頁的效果是從“上半頁”翻轉到“下半頁”,為了讓過程顯得舒緩,我將翻頁的過程設定為1.0秒。翻頁過程耗時1.0秒,因此在真實時間到達某一秒鐘時,需要判斷下一秒是否需要翻頁,如果翻頁,就立刻執行翻頁的過程。

image

翻頁過程不需要改變最底層的X層和Y層,它們繼續靜態顯示即可。以8點13分59秒為例,當判斷下一秒為8點14分時,將立刻生成A層、B層、C層,分別在下圖示意的位置。

image

A層、B層所顯示的數字為當前的13,C層所顯示的數字為下一秒的時間14,當然因為方向的問題C層翻轉之後實際上是“下半層”。

image

一旦開始旋轉,A層、B層、C層覆蓋X層和Y層,此時的X層和Y層可以提前賦予他們下一秒的時間14。

image

隨著不斷翻轉,0.5秒後,上半層露出下一個時間14,下半層仍然顯示的是當前時間13。

image

0.5秒到1.0秒之間,C層會逐步在下半部顯示,能夠清晰地看到下一個數字為14。翻頁1.0秒之後,時間剛好到達此刻的時間8點14分,A層、B層、C層的使命完成,立刻消失隱藏。X層和Y層提前1秒顯示了正確的時間,翻頁1.0秒後的時間剛好是我們所見到的正確時間8點14分。

如此,翻頁過程結束。

image

​小時的翻頁和分鐘的翻頁實際上是一樣的,只是小時翻頁的過程伴隨著分鐘同時翻頁,例如8點59分59秒的下一秒是9點00分,因此兩個翻頁將同時進行,而基本原理是一樣的。

相關程式碼

在我的程式碼實現中,「翻頁時鐘」和「檢測時間」兩個函式是分開獨立的,因此時鐘、分鐘甚至秒鐘都可以單獨執行翻頁。

最後,分享出OneClock的下載連結和翻頁函式的具體Swift程式碼:

OneClock下載:https://itunes.apple.com/cn/app/id1257395357

翻頁函式:

func rotation(A:UIView,B:UIView,C:UIView){

    A.alpha = 1

    B.alpha = 1

    C.alpha = 1

    rotationFirst(view: B)

    //本文中提到的B,顯示13

    rotationSecond(view: C)

    //本文中提到的C,顯示14

    self.perform(#selector(self.initializeABC),with: nil, afterDelay: 0.9)

    //最後為了過度順利,提前0.1秒讓A/B/C小時

    //initializeABC函式設定A/B/C隱藏

}
複製程式碼
func rotationFirst(view:UIView){

    //舊值標籤,先出來

    let animation = CABasicAnimation(keyPath: "transform.rotation.x")

    animation.fromValue = (-10/360)*Double.pi

    animation.toValue = (-355/360)*Double.pi

    animation.duration = 1.0

    animation.repeatCount = 0

    animation.delegate = selfas? CAAnimationDelegate

    view.layer.add(animation, forKey: "rotationSecond")

    view.alpha = 1

}
複製程式碼
func rotationSecond(view:UIView) {

    //新值標籤,後

    let animation = CABasicAnimation(keyPath: "transform.rotation.x")

    animation.fromValue = (355/360) * Double.pi

    animation.toValue = (10/360) * Double.pi

    animation.duration = 1.0

    animation.repeatCount = 0

    animation.delegate = self as? CAAnimationDelegate

    view.layer.add(animation, forKey: "rotationFirst")

    view.alpha = 1

}

複製程式碼

GitHub:OneSwift - iOS Tips Based On Swift

微博:xDEHANG

相關文章