在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 教程/ iOS/ 自定義 ViewController 容器轉(zhuǎn)場(chǎng)
與四軸無(wú)人機(jī)的通訊
在沙盒中編寫(xiě)腳本
結(jié)構(gòu)體和值類(lèi)型
深入理解 CocoaPods
UICollectionView + UIKit 力學(xué)
NSString 與 Unicode
代碼簽名探析
測(cè)試
架構(gòu)
第二期-并發(fā)編程
Metal
自定義控件
iOS 中的行為
行為驅(qū)動(dòng)開(kāi)發(fā)
Collection View 動(dòng)畫(huà)
截圖測(cè)試
MVVM 介紹
使 Mac 應(yīng)用數(shù)據(jù)腳本化
一個(gè)完整的 Core Data 應(yīng)用
插件
字符串
為 iOS 建立 Travis CI
先進(jìn)的自動(dòng)布局工具箱
動(dòng)畫(huà)
為 iOS 7 重新設(shè)計(jì) App
XPC
從 NSURLConnection 到 NSURLSession
Core Data 網(wǎng)絡(luò)應(yīng)用實(shí)例
GPU 加速下的圖像處理
自定義 Core Data 遷移
子類(lèi)
與調(diào)試器共舞 - LLDB 的華爾茲
圖片格式
并發(fā)編程:API 及挑戰(zhàn)
IP,TCP 和 HTTP
動(dòng)畫(huà)解釋
響應(yīng)式 Android 應(yīng)用
初識(shí) TextKit
客戶端
View-Layer 協(xié)作
回到 Mac
Android
Core Image 介紹
自定義 Formatters
Scene Kit
調(diào)試
項(xiàng)目介紹
Swift 的強(qiáng)大之處
測(cè)試并發(fā)程序
Android 通知中心
調(diào)試:案例學(xué)習(xí)
從 UIKit 到 AppKit
iOS 7 : 隱藏技巧和變通之道
安全
底層并發(fā) API
消息傳遞機(jī)制
更輕量的 View Controllers
用 SQLite 和 FMDB 替代 Core Data
字符串解析
終身學(xué)習(xí)的一代人
視頻
Playground 快速原型制作
Omni 內(nèi)部
同步數(shù)據(jù)
設(shè)計(jì)優(yōu)雅的移動(dòng)游戲
繪制像素到屏幕上
相機(jī)與照片
音頻 API 一覽
交互式動(dòng)畫(huà)
常見(jiàn)的后臺(tái)實(shí)踐
糟糕的測(cè)試
避免濫用單例
數(shù)據(jù)模型和模型對(duì)象
Core Data
字符串本地化
View Controller 轉(zhuǎn)場(chǎng)
照片框架
響應(yīng)式視圖
Square Register 中的擴(kuò)張
DTrace
基礎(chǔ)集合類(lèi)
視頻工具箱和硬件加速
字符串渲染
讓東西變得不那么糟
游戲中的多點(diǎn)互聯(lián)
iCloud 和 Core Data
Views
虛擬音域 - 聲音設(shè)計(jì)的藝術(shù)
導(dǎo)航應(yīng)用
線程安全類(lèi)的設(shè)計(jì)
置換測(cè)試: Mock, Stub 和其他
Build 工具
KVC 和 KVO
Core Image 和視頻
Android Intents
在 iOS 上捕獲視頻
四軸無(wú)人機(jī)項(xiàng)目
Mach-O 可執(zhí)行文件
UI 測(cè)試
值對(duì)象
活動(dòng)追蹤
依賴注入
Swift
項(xiàng)目管理
整潔的 Table View 代碼
Swift 方法的多面性
為什么今天安全仍然重要
Core Data 概述
Foundation
Swift 的函數(shù)式 API
iOS 7 的多任務(wù)
自定義 Collection View 布局
測(cè)試 View Controllers
訪談
收據(jù)驗(yàn)證
數(shù)據(jù)同步
自定義 ViewController 容器轉(zhuǎn)場(chǎng)
游戲
調(diào)試核對(duì)清單
View Controller 容器
學(xué)無(wú)止境
XCTest 測(cè)試實(shí)戰(zhàn)
iOS 7
Layer 中自定義屬性的動(dòng)畫(huà)
第一期-更輕量的 View Controllers
精通 iCloud 文檔存儲(chǔ)
代碼審查的藝術(shù):Dropbox 的故事
GPU 加速下的圖像視覺(jué)
Artsy
照片擴(kuò)展
理解 Scroll Views
使用 VIPER 構(gòu)建 iOS 應(yīng)用
Android 中的 SQLite 數(shù)據(jù)庫(kù)支持
Fetch 請(qǐng)求
導(dǎo)入大數(shù)據(jù)集
iOS 開(kāi)發(fā)者的 Android 第一課
iOS 上的相機(jī)捕捉
語(yǔ)言標(biāo)簽
同步案例學(xué)習(xí)
依賴注入和注解,為什么 Java 比你想象的要好
編譯器
基于 OpenCV 的人臉識(shí)別
玩轉(zhuǎn)字符串
相機(jī)工作原理
Build 過(guò)程

自定義 ViewController 容器轉(zhuǎn)場(chǎng)

話題 #5 中,Chris Eidhof 向我們介紹了 iOS7 引入的新特性自定義 View Controller 轉(zhuǎn)場(chǎng). 他給出了一個(gè) 結(jié)論

我們?cè)诒疚闹惶接懥嗽?navigation controller 中的兩個(gè) view controller 之間的轉(zhuǎn)場(chǎng)動(dòng)畫(huà),但是這些做法在 tab bar controller 或者任何你自己定義的 view controller 容器也是通用的

盡管從技術(shù)角度來(lái)講,使用 iOS 7 的 API,你可以對(duì)自定義容器中的 view controllers 做自定義轉(zhuǎn)場(chǎng),但是這不是能直接使用的,實(shí)現(xiàn)這種效果非常不容易。

請(qǐng)注意我正在討論的自定義視圖控制器容器 (custom container view controllers) 都是 UIViewController 的直接子類(lèi),而不是 UITabBarController 或者 UINavigationController 的子類(lèi)。

對(duì)于你自定義的繼承于 UIViewController 的容器子類(lèi),并沒(méi)有現(xiàn)成可用的 API 允許一個(gè)任意的動(dòng)畫(huà)控制器 (animation controller) 將一個(gè)子視圖控制器自動(dòng)轉(zhuǎn)場(chǎng)到另外一個(gè),不管是可交互式的轉(zhuǎn)場(chǎng)還是不可交互式的轉(zhuǎn)場(chǎng)。 我甚至都覺(jué)著蘋(píng)果根本就不想支持這種方式。蘋(píng)果支持下面的這幾種轉(zhuǎn)場(chǎng)方式:

  • Navigation controller 推入和推出頁(yè)面
  • Tab bar controller 選擇的改變
  • Modal 頁(yè)面的展示和消失

在本文中,我將向你展示如何自定義視圖控制器容器,并且使其支持第三方的動(dòng)畫(huà)控制器。

如果你需要復(fù)習(xí)一下 iOS 5 引入的視圖控制器容器,請(qǐng)閱讀話題#1Ricky Gregersen 寫(xiě)的文章 “View Controller 容器”。

預(yù)熱準(zhǔn)備

看到這里,你可能對(duì)上文我們說(shuō)到的一些問(wèn)題犯嘀咕,讓我來(lái)告訴你答案吧:

為什么我們不直接繼承 UINavigationControllerUITabBarController,并且使用它們提供的功能的?

有些時(shí)候這是你不想要的??赡苣阆胍粋€(gè)非常特殊的外觀或者行為,和這些類(lèi)能夠提供給你的差別非常大,因此你必須使用一些黑客式的手段去達(dá)到你想要的結(jié)果,同時(shí)還要擔(dān)心系統(tǒng)框架的版本更新后這些黑客式的手段是否還仍然有效?;蛘?,你就是想完全控制你的視圖控制器容器,避免不得不支持一些特定的功能。

好吧, 那么為什么不使用 transitionFromViewController:toViewController:duration:options:animations:completion: 去實(shí)現(xiàn)呢?

這又是一個(gè)好問(wèn)題,你可能想用這種方式去實(shí)現(xiàn),但是或許你對(duì)代碼的整潔性比較在意,想把這種轉(zhuǎn)場(chǎng)相關(guān)的代碼封裝在內(nèi)部。那么為什么不使用一個(gè)既存的、被良好驗(yàn)證的設(shè)計(jì)模式呢?這種設(shè)計(jì)模式可以非常方便的支持第三方的轉(zhuǎn)場(chǎng)動(dòng)畫(huà)。

介紹相關(guān)的API

在我們開(kāi)始寫(xiě)代碼之前,讓我們先花一分鐘的時(shí)間來(lái)簡(jiǎn)單看一下我們需要的組件吧。

iOS 7 自定義視圖控制器轉(zhuǎn)場(chǎng)的 API 基本上都是以協(xié)議的方式提供的,這也使其可以非常靈活的使用,因?yàn)槟憧梢院芎?jiǎn)單地將它們插入到你的類(lèi)中。最主要的五個(gè)組件如下:

  1. 動(dòng)畫(huà)控制器 (Animation Controllers) 遵從 UIViewControllerAnimatedTransitioning 協(xié)議,并且負(fù)責(zé)實(shí)際執(zhí)行動(dòng)畫(huà)。
  2. 交互控制器 (Interaction Controllers) 通過(guò)遵從 UIViewControllerInteractiveTransitioning 協(xié)議來(lái)控制可交互式的轉(zhuǎn)場(chǎng)。
  3. 轉(zhuǎn)場(chǎng)代理 (Transitioning Delegates) 根據(jù)不同的轉(zhuǎn)場(chǎng)類(lèi)型方便的提供需要的動(dòng)畫(huà)控制器和交互控制器。
  4. 轉(zhuǎn)場(chǎng)上下文 (Transitioning Contexts) 定義了轉(zhuǎn)場(chǎng)時(shí)需要的元數(shù)據(jù),比如在轉(zhuǎn)場(chǎng)過(guò)程中所參與的視圖控制器和視圖的相關(guān)屬性。 轉(zhuǎn)場(chǎng)上下文對(duì)象遵從 UIViewControllerContextTransitioning 協(xié)議,并且這是由系統(tǒng)負(fù)責(zé)生成和提供的。
  5. 轉(zhuǎn)場(chǎng)協(xié)調(diào)器(Transition Coordinators) 可以在運(yùn)行轉(zhuǎn)場(chǎng)動(dòng)畫(huà)時(shí),并行的運(yùn)行其他動(dòng)畫(huà)。 轉(zhuǎn)場(chǎng)協(xié)調(diào)器遵從 UIViewControllerTransitionCoordinator 協(xié)議。

正如你從其他的閱讀材料中得知的那樣,轉(zhuǎn)場(chǎng)有不可交互式和可交互式兩種方式。在本文中,我們將集中精力于不可交互的轉(zhuǎn)場(chǎng)。這種轉(zhuǎn)場(chǎng)是最簡(jiǎn)單的轉(zhuǎn)場(chǎng),也是我們學(xué)習(xí)的一個(gè)好的開(kāi)始。這意味著我們需要處理上面提到的動(dòng)畫(huà)控制器 (animation controllers),轉(zhuǎn)場(chǎng)代理 (transitioning delegates)轉(zhuǎn)場(chǎng)上下文 (transitioning contexts)。

閑話少說(shuō),讓我們開(kāi)始動(dòng)手吧…

示例工程

通過(guò)三個(gè)階段,我們將要實(shí)現(xiàn)一個(gè)簡(jiǎn)單自定義的視圖控制器容器,它可以對(duì)子視圖控制器提供自定義的轉(zhuǎn)場(chǎng)動(dòng)畫(huà)的支持。

你可以在這里找到這三個(gè)階段的 Xcode 工程的源代碼。

階段 1: 基礎(chǔ)

我們應(yīng)用中的核心類(lèi)是 ContainerViewController,它持有一個(gè)UIViewController實(shí)例的數(shù)組,每個(gè)實(shí)例是一個(gè)普通的 ChildViewController。容器視圖控制器設(shè)置了一個(gè)帶有可點(diǎn)擊圖標(biāo),并代表每個(gè)子視圖控制器的私有的子視圖:

http://wiki.jikexueyuan.com/project/objc/images/12-20.gif" alt="" />

我們通過(guò)點(diǎn)擊圖標(biāo)在不同的子視圖控制器之間切換。在這一階段,子視圖控制器之間切換時(shí)是沒(méi)有轉(zhuǎn)場(chǎng)動(dòng)畫(huà)的。

你可以在這里查看階段-1的源代碼。

階段 2: 轉(zhuǎn)場(chǎng)動(dòng)畫(huà)

當(dāng)我們添加轉(zhuǎn)場(chǎng)動(dòng)畫(huà)時(shí),我們想要使用一個(gè)遵從 UIViewControllerAnimatedTransitioning 協(xié)議的動(dòng)畫(huà)控制器(animation controllers)。這個(gè)協(xié)議聲明了 3 個(gè)方法,前面的 2 個(gè)方法是必須實(shí)現(xiàn)的:

- (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext;
- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext;
- (void)animationEnded:(BOOL)transitionCompleted;  

通過(guò)這些方法,我們可以獲得我們所需的所有東西。當(dāng)我們的視圖控制器容器準(zhǔn)備執(zhí)行動(dòng)畫(huà)時(shí),我們可以從動(dòng)畫(huà)控制器中獲取動(dòng)畫(huà)的持續(xù)時(shí)間,并讓其去執(zhí)行真正的動(dòng)畫(huà)。當(dāng)動(dòng)畫(huà)執(zhí)行完畢后,如果動(dòng)畫(huà)控制器實(shí)現(xiàn)了可選的 animationEnded: 方法,我們可以調(diào)用動(dòng)畫(huà)控制器中的 animationEnded: 方法。

但是,首先我們必須把一件事情搞清楚。正如你在上面的方法簽名中看到的那樣,上面兩個(gè)必須實(shí)現(xiàn)的方法需要一個(gè)轉(zhuǎn)場(chǎng)上下文參數(shù),這是一個(gè)遵從 UIViewControllerContextTransitioning 協(xié)議的對(duì)象。通常情況下,當(dāng)我們使用系統(tǒng)內(nèi)建的類(lèi)時(shí),系統(tǒng)框架為我們創(chuàng)建了轉(zhuǎn)場(chǎng)上下文對(duì)象,并把它傳遞給動(dòng)畫(huà)控制器。但是在我們這種情況下,我們需要自定義轉(zhuǎn)場(chǎng)動(dòng)畫(huà),所以我們需要承擔(dān)系統(tǒng)框架的責(zé)任,自己去創(chuàng)建這個(gè)轉(zhuǎn)場(chǎng)上下文對(duì)象。

這就是大量使用協(xié)議的方便之處。我們可以不用必須復(fù)寫(xiě)一個(gè)私有類(lèi),而復(fù)寫(xiě)私有類(lèi)這種方法是明顯不可行的。我們可以定義自己的類(lèi),并使其遵從文檔中相應(yīng)的協(xié)議就可以了。

盡管在 UIViewControllerContextTransitioning 協(xié)議中聲明了很多方法,而且它們都是必須要實(shí)現(xiàn) (required) 的,但是我們現(xiàn)在可以暫時(shí)忽略它們中的一些方法,因?yàn)槲覀儸F(xiàn)在僅僅支持不可交互式的轉(zhuǎn)場(chǎng)。

同 UIKit 類(lèi)似,我們定義了一個(gè)私有類(lèi) NSObject <UIViewControllerContextTransitioning>。在我們的特定例子中,這個(gè)私有類(lèi)是 PrivateTransitionContext,它的初始化方法如下實(shí)現(xiàn):

- (instancetype)initWithFromViewController:(UIViewController *)fromViewController toViewController:(UIViewController *)toViewController goingRight:(BOOL)goingRight {
    NSAssert ([fromViewController isViewLoaded] && fromViewController.view.superview, @"The fromViewController view must reside in the container view upon initializing the transition context.");

    if ((self = [super init])) {
        self.presentationStyle = UIModalPresentationCustom;
        self.containerView = fromViewController.view.superview;
        self.viewControllers = @{
            UITransitionContextFromViewControllerKey:fromViewController,
            UITransitionContextToViewControllerKey:toViewController,
        };

        CGFloat travelDistance = (goingRight ? -self.containerView.bounds.size.width : self.containerView.bounds.size.width);
        self.disappearingFromRect = self.appearingToRect = self.containerView.bounds;
        self.disappearingToRect = CGRectOffset (self.containerView.bounds, travelDistance, 0);
        self.appearingFromRect = CGRectOffset (self.containerView.bounds, -travelDistance, 0);
    }

    return self;
}

我們把視圖的出現(xiàn)和消失時(shí)的狀態(tài)記錄了下來(lái),比如初始狀態(tài)和最終狀態(tài)的 frame。

請(qǐng)注意一點(diǎn),我們的初始化方法需要我們提供我們是在向右切換還是向左切換。在我們的 ContainerViewController 中,按鈕是一個(gè)接一個(gè)水平排列的,轉(zhuǎn)場(chǎng)上下文通過(guò)設(shè)置每個(gè)的 frame 來(lái)記錄它們之間的位置關(guān)系。動(dòng)畫(huà)控制器或者說(shuō) animator,在生成動(dòng)畫(huà)時(shí)可以使用這些 frame。

我們也可以通過(guò)另外的方式去獲取這些信息,但是那樣的話,就會(huì)使 animator 和 ContainerViewController 及其視圖控制器耦合在一起了,這是不好的,我們并不想這樣。animator 應(yīng)該只關(guān)心它自己以及傳遞給它的上下文,因?yàn)檫@樣,在理想情況下,animator 可以在不同的上下文中得到復(fù)用。

在下一步實(shí)現(xiàn)我們自己的動(dòng)畫(huà)控制器時(shí),我們應(yīng)該時(shí)刻記住這一點(diǎn),現(xiàn)在讓我們來(lái)實(shí)現(xiàn)轉(zhuǎn)場(chǎng)上下文吧。

你可能記得我們?cè)?issue #5 中的View Controller 轉(zhuǎn)場(chǎng)已經(jīng)做過(guò)相同的事情了,為什么我們不使用它呢?事實(shí)上,由于使用了非常靈活的協(xié)議,我們可以直接把那個(gè)工程中的動(dòng)畫(huà)控制器,也就是 Animator 類(lèi)直接拿過(guò)來(lái)使用,不需要任何修改。

使用 Animator 類(lèi)的實(shí)例來(lái)做轉(zhuǎn)場(chǎng)動(dòng)畫(huà)的核心代碼如下所示:

[fromViewController willMoveToParentViewController:nil];
[self addChildViewController:toViewController];

Animator *animator = [[Animator alloc] init];

NSUInteger fromIndex = [self.viewControllers indexOfObject:fromViewController];
NSUInteger toIndex = [self.viewControllers indexOfObject:toViewController];
PrivateTransitionContext *transitionContext = [[PrivateTransitionContext alloc] initWithFromViewController:fromViewController toViewController:toViewController goingRight:toIndex > fromIndex];

transitionContext.animated = YES;
transitionContext.interactive = NO;
transitionContext.completionBlock = ^(BOOL didComplete) {
    [fromViewController.view removeFromSuperview];
    [fromViewController removeFromParentViewController];
    [toViewController didMoveToParentViewController:self];
};

[animator animateTransition:transitionContext];

這其中的大部分是在對(duì)視圖控制器容器的操作,計(jì)算出我們是在向左切換還是向右切換。做動(dòng)畫(huà)的部分基本上只有 3 行代碼:1) 創(chuàng)建 animator,2) 創(chuàng)建轉(zhuǎn)場(chǎng)上下文,和 3) 觸發(fā)動(dòng)畫(huà)執(zhí)行。

有了上面的代碼,轉(zhuǎn)場(chǎng)效果看起來(lái)如下圖所示:

http://wiki.jikexueyuan.com/project/objc/images/12-21.gif" alt="" />

非常酷,我們甚至沒(méi)有寫(xiě)一行動(dòng)畫(huà)相關(guān)的代碼。

你可以在 階段-2 標(biāo)簽下看到這部分代碼的變化。在與 階段-1 的對(duì)比這里你可以看到 階段-2 和 階段-1 相對(duì)比的完整的代碼改變。

階段 3: 封裝

我想我們最后要做的一件事情是封裝 ContainerViewController ,使其能夠:

  1. 提供默認(rèn)的轉(zhuǎn)場(chǎng)動(dòng)畫(huà)。
  2. 提供替換默認(rèn)動(dòng)畫(huà)控制器的代理。

這意味著我們需要把對(duì) Animator 類(lèi)的依賴移除,同時(shí)需要?jiǎng)?chuàng)建一個(gè)代理協(xié)議。

我們?nèi)缦露x這個(gè)協(xié)議:

@protocol ContainerViewControllerDelegate <NSObject>
@optional
- (void)containerViewController:(ContainerViewController *)containerViewController didSelectViewController:(UIViewController *)viewController;
- (id <UIViewControllerAnimatedTransitioning>)containerViewController:(ContainerViewController *)containerViewController animationControllerForTransitionFromViewController:(UIViewController *)fromViewController toViewController:(UIViewController *)toViewController;
@end

containerViewController:didSelectViewController: 方法使 ContainerViewController 可以很更容易的集成于功能齊全的應(yīng)用中。

containerViewController:animationControllerForTransitionFromViewController:toViewController: 方法挺有趣的,當(dāng)然,你可以把它和下面的 UIKit 中的視圖控制器容器的代理協(xié)議做對(duì)比:

  • tabBarController:animationControllerForTransitionFromViewController:toViewController: (UITabBarControllerDelegate)
  • navigationController:animationControllerForOperation:fromViewController:toViewController: (UINavigationControllerDelegate)

所有的這些方法都返回一個(gè) id<UIViewControllerAnimatedTransitioning> 對(duì)象。

與之前一直使用一個(gè) Animator 對(duì)象不同, 我們現(xiàn)在可以從我們的代理那里獲取一個(gè)動(dòng)畫(huà)控制器:

id<UIViewControllerAnimatedTransitioning>animator = nil;
if ([self.delegate respondsToSelector:@selector (containerViewController:animationControllerForTransitionFromViewController:toViewController:)]) {
    animator = [self.delegate containerViewController:self animationControllerForTransitionFromViewController:fromViewController toViewController:toViewController];
}
animator = (animator ?: [[PrivateAnimatedTransition alloc] init]);

如果我們有代理并且它返回了一個(gè) animator,那么我們就使用這個(gè) animator。否則,我們使用內(nèi)部私有類(lèi) PrivateAnimatedTransition 創(chuàng)建一個(gè)默認(rèn)的 animator。接下來(lái)我們將實(shí)現(xiàn) PrivateAnimatedTransition 類(lèi)。

盡管默認(rèn)的動(dòng)畫(huà)和 Animator 有一些不同,但是代碼看起來(lái)驚人的相似。下面是完整的代碼實(shí)現(xiàn):

@implementation PrivateAnimatedTransition

static CGFloat const kChildViewPadding = 16;
static CGFloat const kDamping = 0.75f;
static CGFloat const kInitialSpringVelocity = 0.5f;

- (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext {
    return 1;
}

- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext {

    UIViewController* toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
    UIViewController* fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];

    // When sliding the views horizontally, in and out, figure out whether we are going left or right.
    BOOL goingRight = ([transitionContext initialFrameForViewController:toViewController].origin.x < [transitionContext finalFrameForViewController:toViewController].origin.x);

    CGFloat travelDistance = [transitionContext containerView].bounds.size.width + kChildViewPadding;
    CGAffineTransform travel = CGAffineTransformMakeTranslation (goingRight ? travelDistance : -travelDistance, 0);

    [[transitionContext containerView] addSubview:toViewController.view];
    toViewController.view.alpha = 0;
    toViewController.view.transform = CGAffineTransformInvert (travel);

    [UIView animateWithDuration:[self transitionDuration:transitionContext] delay:0 usingSpringWithDamping:kDamping initialSpringVelocity:kInitialSpringVelocity options:0x00 animations:^{
        fromViewController.view.transform = travel;
        fromViewController.view.alpha = 0;
        toViewController.view.transform = CGAffineTransformIdentity;
        toViewController.view.alpha = 1;
    } completion:^(BOOL finished) {
        fromViewController.view.transform = CGAffineTransformIdentity;
        [transitionContext completeTransition:![transitionContext transitionWasCancelled]];
    }];
}

@end

需要注意的一點(diǎn)是,上面的代碼沒(méi)有通過(guò)設(shè)置視圖的 frame 來(lái)反應(yīng)它們之間的位置關(guān)系,但是代碼仍然可以正常工作,只不過(guò)轉(zhuǎn)場(chǎng)總是在同一個(gè)方向上。因此,這個(gè)類(lèi)也可以被其他的代碼庫(kù)使用。

轉(zhuǎn)場(chǎng)動(dòng)畫(huà)現(xiàn)在看起來(lái)如下所示:

http://wiki.jikexueyuan.com/project/objc/images/12-22.gif" alt="" />

階段-3 的代碼中,app delegate 中設(shè)置代理的部分被注釋掉了,這樣就可以看到默認(rèn)的動(dòng)畫(huà)效果了。你可以將其設(shè)置回再使用 Animator 類(lèi)。你可能想查看同 階段-2 相比所有的修改。

我們現(xiàn)在有一個(gè)自包含的提供了默認(rèn)轉(zhuǎn)場(chǎng)動(dòng)畫(huà)的 ContainerViewController 類(lèi),這個(gè)默認(rèn)的轉(zhuǎn)場(chǎng)動(dòng)畫(huà)可以被開(kāi)發(fā)者自己定義的iOS 7 自定義動(dòng)畫(huà)控制器 (UIViewControllerAnimatedTransitioning) 的對(duì)象代替,甚至都可以不用關(guān)心我們的源代碼就可以方便的替換。

結(jié)論

在本文中我們通過(guò)使用 iOS 7 提供的自定義視圖控制器轉(zhuǎn)場(chǎng)的新特性,使我們自定義的視圖控制器容器成為了 UIKit 的一等公民。

這意味著你可以把自定義的非交互式的轉(zhuǎn)場(chǎng)動(dòng)畫(huà)應(yīng)用到自定義的視圖控制器容器中。你可以看到我們把 7 個(gè)話題之前使用的轉(zhuǎn)場(chǎng)類(lèi)直接拿過(guò)來(lái)使用,而且沒(méi)有做任何修改。

譯者注issue #5 中的 View Controller 轉(zhuǎn)場(chǎng)中的 Animator 類(lèi)。

如果你想讓自己的容器視圖控制器作為一個(gè)類(lèi)庫(kù)或者框架,或者僅僅想使你的代碼得到更好的復(fù)用,這將是非常完美的。

我們現(xiàn)在僅僅支持非交互式的轉(zhuǎn)場(chǎng),下一步就是對(duì)交互式的轉(zhuǎn)場(chǎng)也提供支持。

我把它留給你當(dāng)作一個(gè)練習(xí)。這有一些復(fù)雜,因?yàn)槲覀兓旧鲜且7孪到y(tǒng)的行為,而這真的全是猜測(cè)性的工作。

擴(kuò)展資料