自定義過渡動畫

發表於2016-10-22

本文由我們團隊的王瑞華童鞋撰寫。


在iOS 7 釋出之後,UI上的兩個重要的變化是豐富的動畫使用和介面上各個方面對真實物理世界的模擬。然而互動式自定義過渡不是一個新特性,至少在iOS 3.2 中就已經存在了。例如,翻頁動畫就不僅是從一個頁面到另一個的過渡。它是一個互動式過渡——隨著手指移動的過渡。互動式自定義過渡是提升應用品質,使其在 App Store 大放異彩的重要工具。iOS 7 之後 SDK 允許自定義大部分過渡,包括檢視控制器的出現和消失、UINavigationController 的推入和淡出過渡、UITabBarController 的過渡,甚至是集合檢視的佈局變化過渡。

UICollectionView 的過渡動畫

在iOS 7 之後的日曆和照片應用當中,就運用集合檢視的過渡方式實現了一個viewController 向另一個 viewControler 的過渡。在 UICollectionViewController 中引入了 useLayoutToLayoutNavigationTransitions 這一屬性。當此屬性設定為 YES 時,在將 collecionViewController 推入導航控制器之前,推入過渡會使用 -setColletionViewLayout:animated:來完成集合檢視佈局的變化。開發者要做的只是設定 useLayoutToLayoutNavigationTransitions = YES,剩下的交給系統處理便可以。注意,該方法要求兩個 collectionView 擁有相同的資料。

自定義 viewController 過渡

實現 transition delegate 是 transition 動畫和自定義 presentation 的起點。該 transition delegate 就是開發者定義一個物件並遵循 UIViewControllerTransitioningDelegate 協議。下面看看該協議中包含什麼。

示意圖如下:

112376458-9e03ed2b9441b316

解釋了這麼多,對過渡動畫需要遵循的 delegate 已經有了初步的瞭解,下面通過present 的方式實現一個 push 動畫。

  1. 我們首先建立兩個 viewController VC1 和 VC2,我們要實現 VC1 present 出 VC2,同時模擬 push 和 pop 動畫的效果。
  2. 然後我們需要建立出兩個管理過渡動畫的類,用於管理 present 動畫和 dismiss 動畫,兩個管理類大體實現相似。在 viewController類中遵從 UIViewControllerTransitioningDelegate 協議,實現協議方法。

以下是 present 動畫的例項,dismiss 動畫與之相似,不再贅述。

CustomPushAnimation.h

使用互動式自定義過渡

互動式過渡是由事件驅動的。可以是動作事件或者手勢,通常為手勢。要實現一個互動式過渡,除了需要跟之前相同的動畫,還需要告訴互動控制器動畫完成了多少。開發者只需要確定已經完成的百分比,其他交給系統去做就可以了。例如,(平移和縮放的距離 / 速度的量可以作為計算完成的百分比的引數)。

互動式控制器實現了 UIViewControllerInteractiveTransitioning 協議,該協議中包含如下方法:

這個方法裡只能有一個動畫塊,動畫應該基於 UIView 而不是圖層,互動式過渡不支援 CATransitionCALayer 動畫。

互動式過渡的互動控制器應當是 UIPercentDrivenInteractiveTransition 子類。動畫類負責計算完成百分比,系統會自動更新動畫的中間狀態。

根據手勢移動或者縮放的距離,計算出百分比並呼叫相應方法。

下面是簡單的互動式過渡的程式碼片段,該事例只做了互動式 dismiss 的部分,也只羅列了比較關鍵的部分。

SecondViewController.m

CustomInteractiveTransition.m

UIViewControllerTransitionCoordinator 過渡協調器

所有的過渡都會建立一個過渡協調器,無論是否自定義。也就是說,當執行預設的模態過渡或push過渡時,也可以對檢視中的其他部分做動畫。

在 iOS中,可以取消一個過渡。這意味著,第二個檢視的 -viewWillApear 被呼叫,但 -viewDidApear不一定被呼叫。如果程式碼寫的假定 -viewDidAppear 總是在 -viewWillAppear 之後執行則需要重新考慮邏輯實現。這種情況下UIViewControllerTransitionCoordinator 就有用了。在互動式過渡結束的時候,會在 block 中收到通知。

Demo在這

相關文章