毫無疑問,ViewController(在本文中簡寫為VC)是使用MVC構建Cocoa或者CocoaTouch程式時最重要的一個類,我們的日常工作中一般來說最花費時間和精力的也是在為VC部分編寫代碼。蘋果產品是注重使用者體驗的,而對細節進行琢磨也是蘋果對於開發人員一直以來的要求和希望。在使用者體驗中,VC之間的關係,比如不同VC之間遷移和轉換動畫效果一直是一個值得不斷推敲的重點。在iOS7中,蘋果給出了一套完整的VC製作之間遷移效果的方案,可以說是為現在這部分各種不同實現方案指出了一條推薦的統一道路。
iOS 7 SDK之前的VC切換解決方案
在深入iOS 7的VC轉場效果的新API實現之前,先讓我們回顧下現在的一般做法吧。這可以協助理解為什麼iOS7要對VC切換給出新的解決方案,如果您對iOS 5中引入的VC容器比較熟悉的話,可以跳過這節。
在iOS5和iOS6中,除了標準的Push,Tab和PresentModal之外,一般是使用ChildViewController的方式來完成VC之間切換的過渡效果。ChildViewController和自訂的Controller容器是iOS 5 SDK中加入的,可以用來產生自訂的VC容器,簡單來說典型的一種用法類似這樣:
//ContainerVC.m[self addChildViewController:toVC];[fromVC willMoveToParentViewController:nil];[self.view addSubview:toVC.view];__weak id weakSelf = self; [self transitionFromViewController:fromVC toViewController:toVC duration:0.3 options:UIViewAnimationOptionTransitionCrossDissolve animations:^{} completion:^(BOOL finished) { [fromVC.view removeFromSuperView]; [fromVC removeFromParentViewController]; [toVC didMoveToParentViewController:weakSelf];}];
在自己對view進行管理的同時,可以使用transitionFromViewController:toViewController:...的Animation block中可以實現一些簡單的轉場效果。去年年初我寫的UIViewController的誤用一文中曾經指出類似[viewController.view addSubview:someOtherViewController.view];這樣的代碼的存在,一般就是誤用VC。這個結論適用於非Controller容器,對於自訂的Controller容器來說,向當前view上添加其他VC的view是正確的做法(當然不能忘了也將VC本身通過addChildViewController:方法添加到容器中)。
VC容器的主要目的是解決將不同VC添加到同一個螢幕上的需求,以及可以提供一些簡單的自訂切換開關效果。使用VC容器可以使view的關係正確,使添加的VC能夠正確接收到例如旋轉螢幕,viewDidLoad:等VC事件,進而進行正確相應。VC容器確實可以解決一部分問題,但是也應該看到,對於自訂切換開關效果來說,這樣的解決還有很多不足。首先是代碼高度耦合,VC切換部分的代碼直接寫在container中,難以分離重用;其次能夠提供的轉場效果比較有限,只能使用UIView動畫來切換,管理起來也略顯麻煩。iOS 7提供了一套新的自訂VC切換,就是針對這兩個問題的。
iOS 7 自訂ViewController動畫切換自訂動畫切換的相關的主要API
在深入之前,我們先來看看新SDK中有關這部分內容的相關介面以及它們的關係和典型用法。這幾個介面和類的名字都比較相似,但是還是能比較好的描述出各自的職能的,一開始的話可能比較迷惑,但是當自己動手實現一兩個例子之後,它們之間的關係就會逐漸明晰起來。(相關的內容都定義在UIKit的UIViewControllerTransitioning.h中了)
@protocol UIViewControllerContextTransitioning
這個介面用來提供切換上下文給開發人員使用,包含了從哪個VC到哪個VC等各類資訊,一般不需要開發人員自己實現。具體來說,iOS7的自訂切換開關目的之一就是切換相關代碼解耦,在進行VC切換時,做轉場效果實現的時候必須要需要切換前後VC的一些資訊,系統在新加入的API的比較的地方都會提供一個實現了該介面的對象,以供我們使用。
對於切換的動畫實現來說(這裡先介紹簡單的動畫,在後面我會再引入手勢驅動的動畫),這個介面中最重要的方法有: