iOS 8自定義動畫轉場上手指南

原文:http://www.cocoachina.com/ios/20150126/11011.htmlhtml

 

iOS 5發佈的時候,蘋果針對應用程序界面的設計,提出了一種全新的,革命性的方法—Storyboard,它從根本上改變了現有的設計理念。iOS 5以前,每一個視圖控制器一般都伴有一個Interface Builder的文件,叫nib或者xib,這個想法比較簡單:每一個視圖控制器的界面應該在各自的nib文件中設計,而全部的nib文件一塊兒構成了整個應用程序的界面。一方面,這個是很方便的,由於它強迫開發者在界面設計的時候將注意力集中在界面上,但另外一方面,到最後,太多的文件不得不被建立,開發者將不能概覽應用的總體界面。ios

custom-segue-featured-1024.jpg

隨着storyboard的產生,上面的這些都成爲了歷史,由於這種新方法受到了開發者社區的普遍使用。相比老的技術,storyboards提供了三個重要的優點:編程

  1. 整個界面設計只發生在一個文件裏。項目的總文件數量大大減小了,特別是在大項目裏。固然你可使用額外的nib文件,而且容許只建立輔助視圖。swift

  2. 開發者能即時瀏覽應用的界面和流程。閉包

  3. 視圖控制器之間的轉換(界面設計的專業術語叫場景(scene)),以及轉換是如何發生的,在storyboard中已被完美地定義並清楚地呈現給了開發者。app

綜上所述,場景之間的轉換構成storyboard的特殊部分,咱們通常把它叫作轉場(segue)。框架

轉場跟應用的導航和處理是密切相關的,由於它明肯定義了一個視圖切換到另外一個視圖的轉換細節。這些細節指定了是否應用動畫,動畫的類型,固然還有實際轉換時的準備和性能。除此以外,轉場也用來將傳遞數據到下一個視圖控制器裏,這個用法也很常見。編程語言

從編程的角度看,場景是UIStoryboardSegue類的一個對象,它第一次在iOS 5中介紹到。和其它類的對象不一樣的是,這種對象不能直接的建立或使用。不過你能夠指定轉場的屬性,而後在轉場即將發生時提供給它以達到目的。UIKit框架提供了一些帶默認動畫過渡的預約義的轉場,包括:push segues(包括導航控制器的app),帶有動畫選擇的模態轉場(modal segues), popover segues。更高級的狀況下,iOS SDK默認的轉場可能不夠用,因此開發者必須實現他們的自定義轉場(custom segues)。ide

建立一個自定義轉場並不難,由於它是iOS標準編程技術的組成部分。實際上你只須要生成UIStoryboardSegue的子類,並重載一個叫perform的方法便可。這個perform方法中必須實現自定義動畫的邏輯。從一個視圖控制器轉換到另外一個以及返回操做的觸發,也須要由開發者編程提供,這是一個標準的步驟。工具

在本教程中,個人目標是向大家展現如何實現自定義轉場,並經過一個簡單的演示應用介紹這個概念的全部方面。擁有建立自定義轉場的知識, 能夠將你導向開發更強大的app的道路。此外,對於最大化用戶體驗,並開發引人注目的漂亮應用,自定義轉場也頗有幫助。

若是你有興趣學習我剛剛說的話,就一塊兒來探索教程裏的全部細節和自定義轉場的奧祕吧。

應用程序概述

不像我以前幾個教程提供了一個啓動項目,本教程咱們將從頭開始建立app。事實上,我是故意這麼作的,由於,項目中一些重要部分須要用到Interface Builder,因此我認爲從頭開始循序漸進的來作,能讓你看清裏面的細節。

正如我先前所說,咱們將開發一個很是簡單的app,在這個應用中咱們將建立兩個自定義轉場。須要提早說明的是,咱們的演示應用將有三個視圖控制器,也就是在Interface Builder中有三個場景和三個相關類。默認狀況下,第一個是由Xcode建立的,所以咱們只要再添加兩個。咱們將建立的自定義轉場用來導航第一個視圖控制器到第二個(以及返回),以及從第一個到第三個(以及返回)。第二個和第三個視圖控制器之間咱們不添加任何聯繫。

所以,咱們須要建立兩個自定義轉場。由於要包括返回,每個轉場須要建立兩個對應的類(所以,共四個):第一個類裏咱們將實現從第一個視圖控制器到另外一個轉換的全部自定義邏輯。第二個類實現返回到第一個視圖控制器的邏輯,或者換句話說要實現解除轉場(unwind segue)。後面會講到解除轉場,如今只須要記住這就是用來讓咱們返回到前一個視圖控制器的轉場。

視圖控制器自己沒什麼須要作的。咱們會用一個label註明視圖控制器的名稱,每個會有一個不一樣的背景顏色,可讓咱們很容易地查看轉換(是的,這將是一個五光十色的應用)。第一個和第二個視圖控制器也會多一個label,其中從其餘視圖控制器傳來的自定義的消息將被顯示出來。

最後,轉場將在如下的動做發生的時候被觸發:

  • 從第一個視圖控制器轉換到第二個,咱們將使用向上滑動的手勢(swipe up).而返回,使用向下滑動的手勢(swipe down)。我不打算描述咱們實現的動畫,我會展現給大家看。

  • 從第一個視圖控制器轉換到第三個,咱們用一個按鈕(UIButton)。而返回,使用向上滑動手勢。對於動畫很少作說明。

固然,咱們也會在視圖控制器之間傳遞數據。

在咱們繼續以前,有個最終demo,將展現咱們將要作的,以及咱們的自定義轉場是如何工做的。

final_sample.gif

注意,建立一個自定義轉場的時候,你能夠實現任何一個你想到的或者須要的動畫。咱們作的時候,你能夠嘗試作下。

建立應用程序

咱們開始啓動Xcode,選擇建立一個新工程。在出現的嚮導中,選擇Single View Application做爲工程的模板。選擇下一步,在Product Name字段裏,設置CustomSegues做爲項目名稱。同時,確保選擇的編程語言是Swift,設備是iPhone。

t26_3_template2.png

選擇下一步。這步中,選擇保存項目的路徑,而後點擊生成按鈕。

如今工程已經準備好了,選擇工程導航對應的組。默認狀況下,General選項卡是打開的,這也是咱們須要的。在Deployment Info部分,不選擇Device Orientation區域裏的Landscape Left 和 Landscape Right選項,只選擇Portrait選項。若是你要在一個iOS 8以前的設備上測試,自由改變從8.1到以前的任意iOS版本deployment target。(最好不要運行在iOS 8以前的設備上)

t26_4_general_tab.png

如今,咱們準備好繼續進行實現,經過第一個界面建立開始。

初始界面設置

第一步是添加咱們在界面裏要用到的視圖控制器。因此,在工程導航欄(Project Navigator)裏點擊Main.storyboard文件,讓Interface Builder顯示出來。在三個不一樣的部分,咱們將打破咱們的工做,每個裏咱們將設置一個視圖控制器。但首先,要確保改變當前的尺寸類到Compact Width 和Regular Height,這樣界面適配iPhone的尺寸。

t26_5_size_classes.png

配置第一個視圖控制器

當打開Interface Builder的時候,你會看到Xcode默認添加的場景。這就是咱們開始的地方。在這個場景裏添加兩個UILabel對象。第一個設置屬性以下:

  • Frame: X=16, Y=77, W=368, H=21

  • Font: System Bold

  • Font size: 24

  • Text: View Controller #1

  • Text alignment: Center

同時,設置上下左右的約束條件:

t26_6_set_constraints1.png

給第二個label,設置以下屬性:

  • Frame: X=16, Y=390, W=368, H=21

  • Text: None

  • Text alignment: Center

而後設它的Horizontal Center in Container, Vertical Center in Container),寬和高的約束條件。

t26_7_set_constraints2_1.pngt26_8_set_constraints2_2.png

完成兩個label的屬性和約束條件設置以後,在場景中添加一個UIButton對象。參數設置以下:

  • Frame: X=169, Y=712, W=62, H=30

  • Title: Tap Me!

  • Text Color: Black

關於它的約束條件,簡單地點擊Interface Builder右下角的大頭針按鈕,選擇Selected Views部分裏的Add Missing Contrains選項。

你完成以後,選擇視圖,改變背景顏色,打開Attributes Inspector裏對應的下拉菜單,選擇「Other…」選項。在顏色選擇器裏,點擊調色板按鈕而後選擇蠟筆*調色板(由於比較柔和一點),關閉顏色選擇器。

t26_9_color_picker.png

下面是第一個場景的截圖:

t26_10_ib_scene1.png

配置第二個視圖控制器

如今關注第二個視圖控制器。在畫布上直接從庫裏拖一個新的控制器對象。而後也添加兩個UILabel對象,並設置和上面同樣的屬性。別忘了設置約束條件。這邊惟一不一樣的地方是第一個label的文本,改成「View Controller #2!」(不帶引號)。

下一步,選擇視圖,再次打開顏色選擇器,此次選擇Honeydew(列表中第二個),而後關閉顏色選擇器。

這時,Xcode將給你個警告,由於兩個視圖控制器之間沒有轉場(segue)。不要緊,咱們立刻就要解決這個問題了。

下面這個圖展現了第二個場景:

t26_11_ib_scene2.png

配置第三個視圖控制器

最後,咱們從對象庫裏再添加一個視圖控制器到畫布上。此次,只添加一個UILabel對象,不是兩個。設置和前兩個場景中第一個label同樣的屬性。有兩個不一樣點:第一,設置label的framde的Y值爲389;第二,設置文本爲「View Controller #3!」。這個視圖裏沒有其餘子視圖了,你只要選擇一個背景顏色。和以前兩次同樣,在顏色選擇器裏選擇sky顏色。

對於它的約束條件,和以前兩個視圖控制器裏的第二個label同樣設置 Horizontal Center in Container, Vertical Center in Container,以及寬和高。設置Y值和約束條件,讓label正好顯示在視圖中間。

界面中第三個場景看起來是這樣的:

t26_12_ib_scene3.png

添加新的視圖控制器類

咱們以前添加到界面上的每個場景,必須設置一個不一樣的類來實現每個細節。默認狀況下,ViewController設定爲每一個場景的類,這很是適合咱們的第一個視圖控制器(這個是Xcode自動建立的)。而其餘兩個,咱們須要建立兩個新類,下面就讓咱們來實現一下。

第一步是建立新的類文件,到Xcode菜單裏File>New>File…,啓動這個過程,引導建立新文件的細節出現了,因此第一步要確保選擇iOS下,Source類別裏的Cocoa Touch Class。

點擊下一步按鈕。在嚮導的第二步,在Subclass of裏:字段選擇或輸入UIViewController的值。而後指定SecondViewController做爲你剛剛建立的名字。固然你不能改變編程語言,確保最後字段裏選擇的是Swift語言。

點擊下一步,生成新的文件。一旦完成,你會看到一個叫SecondViewController.swift的新文件,出如今Project導航器裏。

重複上述過程,給第三個視圖控制器添加類文件。類名設置爲ThirdViewController,剩下的步驟都同樣。

添加完第二個文件後,你應該能在Project導航器裏看到這兩個文件:

t26_15_project_navigator_new_classes.png

咱們回到Interface Builder和新建立場景的類以前,讓咱們先聲明兩個後面要用到的IBOutlet的屬性,在ViewController.swift裏添加以下屬性:

1
@IBOutlet?weak? var ?lblMessage:?UILabel!

在SecondViewController.swift文件裏,添加和上面徹底同樣的設置。這兩個屬性被鏈接到開始的兩個試圖控制器裏的第二個label上,稍後咱們能夠顯示一條消息給它們。

如今再次打開Main.storyboard文件,選擇第二個場景(綠色背景那個)。這個上面點擊視圖控制器對象,進到工具面板裏的Identity inspector裏,在Custom Class部分,具體在Class字段,設置咱們在工程開始時候添加的第一個類:SecondViewController:

t26_16_second_scene_class.png

第三個場景(藍色背景的)也同樣的處理。選擇後,點擊視圖控制器的上面,設置ThirdViewController做爲它的類:

t26_17_third_scene_class.png

好了,如今每一個場景匹配了一個不一樣的類。在這部分的最後,咱們鏈接兩個以前聲明的IBOutlet屬性,從第一個視圖控制器(橙色背景的那個)開始。點擊視圖控制器對象的上面,按住Ctrl拖向場景中的那個label:

t26_18_connect_iboutlet.png

在彈出的小窗口裏,選擇lblMessage屬性,這樣聯繫就完成了。

t26_19_select_iboutlet.png

在SecondViewController場景裏同樣的步驟,關聯那個視圖控制器的lblMessage屬性到場景中的label上。

添加自定義轉場類

自定義轉場的建立包括UIStoryboardSegue的子類化,以及一個必須實現的perform方法。方法中,視圖控制器轉換的自定義邏輯實際是在這裏應用,因此,在寫轉場相關的代碼以前,讓咱們先添加全部必要的類。

工程中添加新類的方法以前已經詳細介紹過了,因此你須要添加文件的時候也能夠將它當成指南。在我給大家每一個文件的細節以前,咱們一共要建立4個文件。由於每一個自定義轉場須要兩個類,咱們將建立兩個文件。具體地說,第一個類用來實現全部的邏輯,以及轉場執行的轉換動畫。第二個類用來實現從第二個視圖控制器到第一個的相反動做。也就是所謂的解除轉場(unwind segue),咱們稍後將詳細介紹。

綜上所述,開始向項目中添加新類。添加每一個文件時注意兩個問題:老是選擇Cocoa Touch Class模板,以及嚮導中第二步的字段,設置Subclass of的值爲UIStoryboardSegue。

咱們將四個文件的名字命名爲:

  • FirstCustomSegue

  • FirstCustomSegueUnwind

  • SecondCustomSegue

  • SecondCustomSegueUnwind

這四個文件加完後都顯示在Project導航器裏了。

建立第一個自定義轉場

如今讓咱們開始第一個自定義轉場。寫代碼以前,必須在Interface Builder裏添加轉場,給咱們想應用自定義轉換的地方聯繫兩個場景。本例中,咱們將建立的轉場是從ViewController場景(橙色背景)到SecondViewController場景(綠色背景)。

再次打開Main.storyboard,簡單地建立新轉場(Segue),擴大文檔大綱,若是它被隱藏的話,選擇ViewController場景裏的ViewController對象:

t26_21_document_outline.png

而後,按住Ctrl將SecondViewController拖向下面的SecondViewController場景中:

t26_22_create_segue_connect.png

關於新的轉場,彈出個有不少選項的黑色彈出框。其中有個叫custom:

t26_23_create_segue_select_custom.png

點擊它,轉場就立馬創建了。你能夠經過檢查畫布中是否添加了一根鏈接兩個場景的連線進行驗證。

t26_24_segue_line.png

咱們開始寫代碼以前還有些設置要完成。首先,點擊選擇畫布上的轉場,打開Utilities面板裏的屬性檢查器(Attributes inspector)。咱們要作得最重要的一個任務是,設置轉場的identifier值,在代碼中會用到這個以便咱們引用。真正重要的是不要給多個轉場指定相同的標示符。因此,本例中,設置idFirstSegue爲轉場的標示符。同時在Segue Class字段裏,必須指定咱們用來執行自定義轉換的自定義類。這裏,咱們設置FirstCustomSegue爲自定義轉場的類。運行的時候,程序會執行這個類裏存在的代碼,讓轉場正常執行。

t26_25_set_segue_identifier.png

自定義轉場的實現

如今新的自定義轉場有了,它的設置也指定好了,接下來讓咱們實現第一個視圖控制器到第二個控制器的理想的轉換。簡而言之,寫關於自定義轉場的代碼一般要作的是,「玩」兩個視圖控制器的視圖。首先,目標視圖控制器的視圖的初始狀態是被指定的,而且被手動添加到應用的窗口上。而後使用動畫目標視圖被放到想要放的最終位置,源視圖控制離開屏幕的時候也是動畫的。

注意:轉場對象是指將被當作目標視圖控制器呈現的視圖控制器,而當前的視圖控制器就是源視圖控制器(source view controller)。

最後,當動畫轉換結束的時候,新的視圖控制器將直接呈現給用戶,沒有更多的動畫。

app概述部分的教程中,你已經看到了咱們想要達到的效果。無論轉場怎麼執行,咱們但願第一個視圖控制器的視圖是向上滑動,第二個視圖控制器的視圖跟着動。兩個視圖之間沒有空隙,第二個把第一個給「粘住」了。

如今讓咱們開始寫代碼,咱們一步一步的看。最後,我會一塊兒提供如下方法的全部實現。

打開FirstCustomSegue.swift文件,添加如下方法定義:

1
2
3
override?func?perform()?{
 
}

這個方法已經在UIStoryboardSegue的父類裏定義了,這裏咱們重載這個方法,以便咱們添加想要的自定義邏輯。因此,第一步是使咱們的工做更簡單,它指定視圖的源和目標視圖控制器的兩個局部變量,以下所示:

1
2
3
4
5
6
override?func?perform()?{
???? //?Assign?the?source?and?destination?views?to?local?variables.
???? var ?firstVCView?=?self.sourceViewController.view?as?UIView!
???? var ?secondVCView?=?self.destinationViewController.view?as?UIView!
 
}

另外,咱們須要屏幕的寬和高,而後放在兩個變量裏:

1
2
3
4
5
6
7
8
override?func?perform()?{
????...
 
???? //?Get?the?screen?width?and?height.
????let?screenWidth?=?UIScreen.mainScreen().bounds.size.width
????let?screenHeight?=?UIScreen.mainScreen().bounds.size.height
 
}

好了,如今指定應該出現的視圖的初始位置。考慮到咱們想要視圖從底部移動到上面,咱們把視圖放在屏幕可視區域的外面,當前視圖的正下方。這很簡單,咱們簡單地設置下視圖的frame:

1
2
3
4
5
6
7
override?func?perform()?{
????...
 
???? //?Specify?the?initial?position?of?the?destination?view.
????secondVCView.frame?=?CGRectMake(0.0,?screenHeight,?screenWidth,?screenHeight)
 
}

這時,第二個視圖控制器的視圖還不是窗口的子視圖。因此,在咱們實現真正的動畫以前,很明顯,咱們必須把它加到窗口上。這用窗口對象的方法insertSubview(view:aboveSubview:)來實現。正如你接下來看到的,咱們先訪問窗口對象,而後添加目標視圖:

1
2
3
4
5
6
7
8
override?func?perform()?{
????...
 
???? //?Access?the?app's?key?window?and?insert?the?destination?view?above?the?current?(source)?one.
????let?window?=?UIApplication.sharedApplication().keyWindow
????window?.insertSubview(secondVCView,?aboveSubview:?firstVCView)
 
}

別被上面的話給搞糊塗了。關於窗口子視圖,他們的順序看起來像在棧裏同樣。通常而言它不會帶來麻煩。

最後,讓咱們給轉換過程添加動畫。首先,咱們將第一個視圖控制器的視圖從屏幕上方移出邊緣,同時,把第二個視圖放到第一個的位置上。實際上,所謂的「移動」,就是修改兩個視圖的frame:

1
2
3
4
5
6
7
8
9
10
11
12
13
override?func?perform()?{
????...
 
???? //?Animate?the?transition.
????UIView.animateWithDuration(0.4,?animations:?{?()?->?Void? in ????????
????????firstVCView.frame?=?CGRectOffset(firstVCView.frame,?0.0,?-screenHeight)
????????secondVCView.frame?=?CGRectOffset(secondVCView.frame,?0.0,?-screenHeight)
 
????????})?{?(Finished)?->?Void? in
 
????}
 
}

上面兩行代碼將執行預期的效果。然而,咱們還沒徹底結束,由於咱們還沒顯示出新的視圖控制器(目標視圖控制器)。咱們將在第二個閉包裏實現:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
override?func?perform()?{
????...
 
???? //?Animate?the?transition.
????UIView.animateWithDuration(0.4,?animations:?{?()?->?Void? in
????????firstVCView.frame?=?CGRectOffset(firstVCView.frame,?0.0,?-screenHeight)
????????secondVCView.frame?=?CGRectOffset(secondVCView.frame,?0.0,?-screenHeight)
 
????????})?{?(Finished)?->?Void? in
????????????self.sourceViewController.presentViewController(self.destinationViewController?as?UIViewController,
????????????????animated:? false ,
????????????????completion:?nil)
????}
 
}

動畫部分到這裏就結束了。總結一下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
override?func?perform()?{
???? //?Assign?the?source?and?destination?views?to?local?variables.
???? var ?firstVCView?=?self.sourceViewController.view?as?UIView!
???? var ?secondVCView?=?self.destinationViewController.view?as?UIView!
 
???? //?Get?the?screen?width?and?height.
????let?screenWidth?=?UIScreen.mainScreen().bounds.size.width
????let?screenHeight?=?UIScreen.mainScreen().bounds.size.height
 
???? //?Specify?the?initial?position?of?the?destination?view.
????secondVCView.frame?=?CGRectMake(0.0,?screenHeight,?screenWidth,?screenHeight)
 
???? //?Access?the?app's?key?window?and?insert?the?destination?view?above?the?current?(source)?one.
????let?window?=?UIApplication.sharedApplication().keyWindow
????window?.insertSubview(secondVCView,?aboveSubview:?firstVCView)
 
???? //?Animate?the?transition.
????UIView.animateWithDuration(0.4,?animations:?{?()?->?Void? in
????????firstVCView.frame?=?CGRectOffset(firstVCView.frame,?0.0,?-screenHeight)
????????secondVCView.frame?=?CGRectOffset(secondVCView.frame,?0.0,?-screenHeight)
 
????????})?{?(Finished)?->?Void? in
????????????self.sourceViewController.presentViewController(self.destinationViewController?as?UIViewController,
????????????????animated:? false ,
????????????????completion:?nil)
????}
 
}

在你給app第一次調試以前,咱們還必須執行自定義轉場。這個發生在ViewController視圖控制器的視圖上作向上滑動的手勢。因此,繼續打開ViewController.swift文件。在viewDidLoad方法裏建立一個新的手勢對象,而後把它加到視圖裏:

1
2
3
4
5
6
7
override?func?viewDidLoad()?{
????...
 
???? var ?swipeGestureRecognizer:?UISwipeGestureRecognizer?=?UISwipeGestureRecognizer(target:?self,?action:? "showSecondViewController" )
????swipeGestureRecognizer.direction?=?UISwipeGestureRecognizerDirection.Up
????self.view.addGestureRecognizer(swipeGestureRecognizer)
}

當手勢被執行的時候,showSecondViewController方法應該是被調用的,但還沒實現。所以,讓咱們添加它的定義,這裏咱們將添加簡單的一行代碼來執行自定義轉場:

1
2
3
func?showSecondViewController()?{
????self.performSegueWithIdentifier( "idFirstSegue" ,?sender:?self)
}

能夠注意到,咱們是經過標示符來訪問轉場的。當咱們滑動到視圖,以上的調用使咱們在FirstCustomSegue類裏的自定義實現得以執行。

你如今能夠調試app了。你能夠在模擬器上運行,也能夠在真機上運行。不過,即便你能夠向上滑動來轉換視圖,你不能返回到第一個視圖控制器。這是正常的,由於咱們尚未定義,咱們接下來將實現這個方法。

解除轉場(The Unwind Segue)

建立自定義轉場的時候,須要同時實現導航裏的兩個方法:從源視圖控制器到目標視圖控制器,而後返回。幾乎不可能只創建一個方法。如今咱們已經實現了轉場,因此它將按咱們想要的動畫方式顯示第二個視圖控制器,咱們必須讓app可以作相反的事情。執行返回導航的轉場,叫解除轉場(unwind segue)。

簡而言之,解除轉場和正常的同樣,可是它的配置有點複雜。某些步驟仍是要完成的,但沒有超出標準編程技術以外的東西。注意兩點:

  1. 解除轉場(unwind segue)一般和正常自定義轉場(segue)一塊兒出現。

  2. 要解除轉場起做用,咱們必須重寫perform方法,並應用自定義邏輯和咱們想要的或者應用規定的動畫。另外,導航返回源視圖控制器的過渡效果不須要和對應的正常轉場相同。

解除轉場的實現分四個步驟:

  1. IBAction方法的建立,該方法在解除轉場被執行的時候會選擇地執行一些代碼。這個方法能夠有你想要的任何名字,並且不強制包含其它東西。它須要定義,但能夠留空,解除轉場的定義須要依賴這個方法。

  2. 解除轉場的建立,設置的配置。這和以前咱們在Interface Builder裏的轉場不太同樣,等下咱們將看看這個是怎麼實現的。

  3. 經過重寫UIStoryboardSegue子類裏的perform方法,來實現通常的邏輯。

  4. UIViewController類提供了特定方法的定義,因此係統知道解除轉場即將執行。

如今你能夠會有些迷糊,接下來,咱們會解釋全部的東西。

先從上面提到的第一個步驟裏的IBAction方法開始。這個方法一般在咱們想要導航的初始視圖控制器裏實現。如我所說,方法裏能夠是空的,可是你得記住若是你不定義至少一個這樣的方法,你將沒法繼續。當解除轉場存在在app中,不必使用那麼多的方法。一般狀況下,簡單地定義一個這樣的動做方法,檢測對應的解除轉場對應而後調用,就足夠了。

如今行動,打開ViewController.swift文件,添加以下代碼:

1
2
3
@IBAction?func?returnFromSegueActions(sender:?UIStoryboardSegue){
 
}

咱們將稍後添加些示例代碼。注意這個方法的參數是一個UIStoryboardSegue對象,這個是須要記住的細節。

如今讓咱們去Interface Builder裏,打開Main.storyboard文件。是時候建立解除轉場了。咱們開始檢查SecondViewController場景裏包含的對象,甚至查看場景自己,或者文檔大綱。若是你仔細觀察,你會發現一個對象,叫Exit:

t26_26_exit_1.png
t26_27_exit_2.png

若是你還沒建立過自定義轉場,極可能你不會用到它,可能會想知道這個幹什麼的。這個就是你須要建立的解除轉場。

點擊場景裏SecondViewController對象,按Ctrl拖到Exit對象:

t26_28_unwind_exit.png

下面的彈出框會顯示咱們早前定義的IBAction方法:

t26_29_unwind_popup.png

確保選中它。解除轉場將被建立,你能夠在文檔大綱裏查看到。如今新的聯線被建立了,但轉場在這裏:

t26_30_unwind_segue_listed.png

如今點擊咱們剛建立的解除轉場,打開屬性檢查器。設置「idFirstSegueUnwind」做爲轉場的標示符:

t26_31_set_unwind_segue_identifier.png

解除轉場的第二部分目前已經完成了。接下來咱們要開始寫代碼了,並肯定解除轉場的執行方法。

首先,打開FirstCustomSegueUnWind.swift文件,再次重寫perform方法,並保持對視圖的局部變量的引用。同時,咱們也要在一個變量中保存屏幕高度:

1
2
3
4
5
6
7
override?func?perform()?{
???? //?Assign?the?source?and?destination?views?to?local?variables.
???? var ?secondVCView?=?self.sourceViewController.view?as?UIView!
???? var ?firstVCView?=?self.destinationViewController.view?as?UIView!
 
????let?screenHeight?=?UIScreen.mainScreen().bounds.size.height
}

注意,如今源視圖控制器是SecondViewController,目標視圖控制器是ViewController。繼續,這裏咱們不指定任何視圖的初始狀態,咱們只把第一個視圖控制的視圖(咱們想要返回的那個)加到窗口的子視圖上:

1
2
3
4
5
6
7
override?func?perform()?{
????...
 
????let?window?=?UIApplication.sharedApplication().keyWindow
????window?.insertSubview(firstVCView,?aboveSubview:?secondVCView)
 
}

最後,咱們必須激活兩個視圖的運動。此次,他們都往底部移動:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
override?func?perform()?{
????...
 
???? //?Animate?the?transition.
????UIView.animateWithDuration(0.4,?animations:?{?()?->?Void? in ????????
????????firstVCView.frame?=?CGRectOffset(firstVCView.frame,?0.0,?screenHeight)
????????secondVCView.frame?=?CGRectOffset(secondVCView.frame,?0.0,?screenHeight)
 
????????})?{?(Finished)?->?Void? in
 
????????????self.sourceViewController.dismissViewControllerAnimated( false ,?completion:?nil)
????}
 
 
}

經過改變兩個視圖的y值,咱們設法把他們在預約義動畫的時間內放到新的位置上。當轉換結束,咱們只要讓第二個視圖控制器直接消失,不帶任何動畫,而後就結束了。下面一塊兒給你這個方法的實現:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
override?func?perform()?{
???? //?Assign?the?source?and?destination?views?to?local?variables.
???? var ?secondVCView?=?self.sourceViewController.view?as?UIView!
???? var ?firstVCView?=?self.destinationViewController.view?as?UIView!
 
????let?screenHeight?=?UIScreen.mainScreen().bounds.size.height
 
????let?window?=?UIApplication.sharedApplication().keyWindow
????window?.insertSubview(firstVCView,?aboveSubview:?secondVCView)
 
???? //?Animate?the?transition.
????UIView.animateWithDuration(0.4,?animations:?{?()?->?Void? in
????????firstVCView.frame?=?CGRectOffset(firstVCView.frame,?0.0,?screenHeight)
????????secondVCView.frame?=?CGRectOffset(secondVCView.frame,?0.0,?screenHeight)
 
????????})?{?(Finished)?->?Void? in
 
????????????self.sourceViewController.dismissViewControllerAnimated( false ,?completion:?nil)
????}
}

目前爲止還好,咱們成功建立了初始化要求的IBAction方法和解除轉場,實現了動畫轉換執行的自定義邏輯。如今,還剩最後一個標準方法須要實現,那個方法裏,咱們會使用FirstCustomSegueUnwind類。

打開ViewController.swift文件,定義一下方法:

1
2
3
override?func?segueForUnwindingToViewController(toViewController:?UIViewController,?fromViewController:?UIViewController,?identifier:?String?)?->?UIStoryboardSegue?{
 
}

這是UIViewController類提供的方法。在解除轉場執行的時候會自動調用這個方法,其實現是手動添加的。有三個參數:

  1. fromViewController: 當前顯示的視圖控制器,是咱們想讓它消失的。

  2. toViewController: 目標視圖控制器,或者換句話說是咱們想顯示的控制器。

  3. identifier: 將被執行的轉場的標示符。

注意,這個方法返回的是一個轉場對象。咱們要作的很簡單:咱們會用identifier的值來決定要執行的那個轉場,而後初始化一個解除轉場自定義類的對象,這個類對象是咱們最後要返回的。同時,調用一個super的方法,在這裏重載下,讓咱們看看代碼:

1
2
3
4
5
6
7
8
9
10
11
12
override?func?segueForUnwindingToViewController(toViewController:?UIViewController,?fromViewController:?UIViewController,?identifier:?String?)?->?UIStoryboardSegue?{
???? if ?let?id?=?identifier{
???????? if ?id?==? "idFirstSegueUnwind" ?{
????????????let?unwindSegue?=?FirstCustomSegueUnwind(identifier:?id,?source:?fromViewController,?destination:?toViewController,?performHandler:?{?()?->?Void? in
 
????????????})
???????????? return ?unwindSegue
????????}????????
????}
 
???? return ? super .segueForUnwindingToViewController(toViewController,?fromViewController:?fromViewController,?identifier:?identifier)
}

首先,咱們要確認identifier參數有實際的值,因此用if let語句。而後用idFirstSegueUnwind值來確認這個轉場是咱們想要的,在if語句中初始化FirstCustomSegueUnwind類對象。這個對象在if語句中返回,外面咱們返回調用super類以後同一個方法返回的值。

如今解除轉場準備好了。剩下實現的是觸發的它的手勢。打開SecondViewController.swift文件,直接到viewDidLoad方法裏。添加以下代碼:

1
2
3
4
5
6
7
8
override?func?viewDidLoad()?{
????...
 
???? var ?swipeGestureRecognizer:?UISwipeGestureRecognizer?=?UISwipeGestureRecognizer(target:?self,?action:? "showFirstViewController" )
????swipeGestureRecognizer.direction?=?UISwipeGestureRecognizerDirection.Down
????self.view.addGestureRecognizer(swipeGestureRecognizer)
 
}

上面定義的手勢是向下滑動的手勢,恰好與以前的相反。

如今定義showFirstViewController方法:

1
2
3
func?showFirstViewController()?{
????self.performSegueWithIdentifier( "idFirstSegueUnwind" ,?sender:?self)
}

如今一切都準備好了,你能夠再次調試app。此次,你能夠在視圖控制器之間來回導航。

執行操做

前面的部分,咱們聲明瞭一個空方法:returnFromSegueActions(sender:), 咱們說這個方法是必須的,這樣咱們才能建立解除轉場。同時,我也說事後面會添加一些代碼,如今咱們就要添加代碼了。

在這個操做方法中,咱們準備作一個很簡單的任務:改變第一個視圖控制器的背景顏色,而後用UIView的動畫把它恢復到正常狀態。雖然這個操做在真正的app裏面毫無心義,但這是個好的例子,可讓咱們看到解除轉場運行的時候是怎麼操做的。

到ViewController.swift文件,在IBAction方法裏,添加以下內容:

1
2
3
4
5
6
7
8
9
10
@IBAction?func?returnFromSegueActions(sender:?UIStoryboardSegue){
???? if ?sender.identifier?==? "idFirstSegueUnwind" ?{
????????let?originalColor?=?self.view.backgroundColor
????????self.view.backgroundColor?=?UIColor.redColor()
 
????????UIView.animateWithDuration(1.0,?animations:?{?()?->?Void? in
????????????self.view.backgroundColor?=?originalColor
????????})
????}
}

首先檢查這個解除轉場是否是咱們感興趣的那個,而後把背景顏色保存在本地,改爲紅色,而後使用動畫部分的塊,設回到原來的值。

以上清楚地展現了當一個自定義解除轉場被執行的時候你想執行動做的時候你應該怎麼操做。稍後咱們繼續在上面的方法裏添加一些代碼。

傳遞數據

在實現自定義轉場(和解除轉場)的時候,要注意兩點:一,注意你設置的轉換效果,以使你的app提供良好的的用戶體驗。二,執行通常的轉場或者解除轉場的時候,視圖控制器之間的數據交換。

前面部分咱們已經涉及到了第一種狀況,咱們指定了兩個視圖來回切換的動畫轉換。如今咱們要看看是怎麼傳遞數據的。極可能你已經在UIKit預約義的轉場裏用到了這個流程。

在咱們開發的演示app中,咱們不會在一個視圖控制器之間傳遞重要的數據。咱們將簡單的發送一個字符串值給對方,會在咱們早先在ViewController和SecondViewController場景裏添加的第二個標籤上顯示。

首先,打開SecondViewController.swift文件。添加如下的在IBOutlet屬性以後的屬性聲明:

1
var ?message:?NSString!

接下來,咱們要用這個屬性,從ViewController視圖到轉場執行到的視圖控制器,傳遞一個字符串值。

打開ViewController.swift文件,在類裏,添加如下方法的實現:

1
2
3
4
5
6
override?func?prepareForSegue(segue:?UIStoryboardSegue,?sender:?AnyObject?)?{
???? if ?segue.identifier?==? "idFirstSegue" ?{
????????let?secondViewController?=?segue.destinationViewController?as?SecondViewController
????????secondViewController.message?=? "Hello?from?the?1st?View?Controller"
????}
}

上面方法是UIViewController類的一部分。基於咱們要執行的轉場的identifier,咱們訪問目標視圖控制器,也就是本例中的SecondViewController。而後,給SecondViewController類裏的message屬性設置字符串消息。

以上都是你在使用轉場的時候須要傳遞數據到另外一個視圖控制器所須要的。 是由很簡單的方法構成的。

如今再次打開SecondViewController.swift文件。是時候處理message屬性,和展現上面接收到的字符串。在viewDidLoad方法裏,添加以下代碼:

1
2
3
4
5
override?func?viewDidLoad()?{
????...
 
????lblMessage.text?=?message
}

最後,從第二個視圖控制到第一個發送一個字符串值。讓咱們再次實現上面的方法:

1
2
3
4
5
6
override?func?prepareForSegue(segue:?UIStoryboardSegue,?sender:?AnyObject?)?{
???? if ?segue.identifier?==? "idFirstSegueUnwind" ?{
????????let?firstViewController?=?segue.destinationViewController?as?ViewController
????????firstViewController.lblMessage.text?=? "You?just?came?back?from?the?2nd?VC"
????}
}

上面的實現中,注意咱們是直接訪問ViewController類裏的消息label的。這是展現視圖控制器子視圖數據的另外一個方法。請注意,這兩種狀況下有必要經過轉場對象訪問目標視圖控制器。

這幾乎就是在視圖控制器之間傳遞數據的全部步驟了。咱們一會建立的第二個自定義轉場,你會看到最後一種方法,但這裏介紹的是你主要用到的。

若是你須要的話能夠再運行app。此次,兩個視圖控制器裏地第二個label顯示了咱們傳遞的字符串值。注意,咱們在SecondViewController類裏的工做結束了,如今開始咱們將關注工程裏存在的第三個視圖控制器。

建立第二個自定義轉場

以前部分咱們討論到的全部概念,都是你在建立和管理自定義轉場裏須要的。然而,我認爲再建立一個可讓一切更容易消化理解,咱們也能夠看到一些不一樣的東西。全部,讓咱們開始吧。

第一步,要在Interface Builder裏建立自定義轉場,因此在工程導航器裏的Main.storyboard文件裏打開它。

界面再次出如今屏幕上,打開文檔大綱板(若是是閉合的話)。點擊ViewController場景裏的ViewController對象,經過按住Ctrl和鼠標,拖動到ThirdViewController場景裏的ThirdViewController對象。將會出現一個藍色的鏈接線:

t26_32_second_segue_connect.png

在彈出的窗口裏,選擇custom轉場。作完以後,確保咱們剛建立的轉場在你的畫布中看起來是這樣的:

t26_33_second_segue_line.png

點擊上面的線,在工具板裏打開屬性檢查器。這裏你要指定兩個東西:轉場標示符和它的類。對標示符,在Identifier字段裏設置idSecondSegue值。在Segue Class字段裏,鍵入SecondCustomSegue的值,讓app知道在執行新的自定義轉場的時候要用到的類。

t26_34_second_segue_settings.png

第二個自定義轉場已經建立好了,接下來實現咱們想看到的動畫轉換。

實現第二個自定義轉場

正如我在引言裏所說,子類化UIStoryboardSegue類,重載perform方法,你能夠自由地實現你想要的任何轉換。你能夠有簡單地動畫轉換,也能夠是複雜的,或者徹底沒有動畫(可是爲何要建立一個自定義轉場不該用任何自定義動畫效果呢?)。

這個轉場咱們將指定另外一種轉換到第三個視圖控制器的動畫。此次,咱們將實現縮小和放大的效果。具體來講,ViewController視圖控制器的視圖經過按比例縮小視圖來消失,這會致使縮小的效果。另外一方面,第三個視圖控制器的視圖將初始爲極小狀態,一旦動畫執行,它將放大到狀態。這會致使放大的效果。教程的概述部分,你能夠看到程序運行時的效果。

如今讓咱們開始寫代碼。打開SecondCustomSegue.swift文件,和咱們以前兩次作的同樣的,經過賦給局部變量建立視圖控制器的視圖的引用。固然,咱們的實現將發生在perform方法裏:

1
2
3
4
5
override?func?perform()?{
???? var ?firstVCView?=?sourceViewController.view?as?UIView!
???? var ?thirdVCView?=?destinationViewController.view?as?UIView!
 
}

注意,你能夠跳過此步,直接用源和目標視圖控制器屬性裏的視圖。然而,我認爲那樣的話會更清晰,儘管會須要更多幾行的代碼。

如今,咱們把第三個視圖控制器的視圖加到窗口上。這是你應該作的事,不然就沒有轉換過渡到得第二個視圖了。

1
2
3
4
5
6
7
override?func?perform()?{
????...
 
????let?window?=?UIApplication.sharedApplication().keyWindow
????window?.insertSubview(thirdVCView,?belowSubview:?firstVCView)
 
}

如今,咱們能夠指定第三個視圖控制器的視圖的初始狀態。咱們不動它的結構(frame),咱們修改transform屬性,代碼以下:

1
2
3
4
5
6
override?func?perform()?{
????...
 
????thirdVCView.transform?=?CGAffineTransformScale(thirdVCView.transform,?0.001,?0.001)
 
}

正如你看到的,咱們按比例縮小它的寬和高。咱們不設置爲零,由於這樣就徹底沒效果了。一個很小的值也是有利於咱們的目的的。

下一步就是執行動畫。本例中,咱們應用兩個連續的動畫,第一個是縮小源視圖,而後是放大目標視圖。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
override?func?perform()?{
????...
 
????UIView.animateWithDuration(0.5,?animations:?{?()?->?Void? in ????????
????????firstVCView.transform?=?CGAffineTransformScale(thirdVCView.transform,?0.001,?0.001)????????
 
????????})?{?(Finished)?->?Void? in
 
????????????UIView.animateWithDuration(0.5,?animations:?{?()?->?Void? in
????????????????thirdVCView.transform?=?CGAffineTransformIdentity
 
????????????????},?completion:?{?(Finished)?->?Void? in
 
????????????????????firstVCView.transform?=?CGAffineTransformIdentity
????????????????????????????????????????self.sourceViewController.presentViewController(self.destinationViewController?as?UIViewController,?animated:? false ,?completion:?nil)
????????????})
????}
}

動畫發生的時候,第一個視圖變小了,看起來像縮小的效果。在completion handler當中,咱們將對目標視圖控制器反轉上面的動畫。最後,動畫結束後,咱們把第一個視圖恢復到正常狀態,而後展現第三個視圖控制器。

這是整個方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
override?func?perform()?{
???? var ?firstVCView?=?sourceViewController.view?as?UIView!
???? var ?thirdVCView?=?destinationViewController.view?as?UIView!
 
????let?window?=?UIApplication.sharedApplication().keyWindow
????window?.insertSubview(thirdVCView,?belowSubview:?firstVCView)
 
????thirdVCView.transform?=?CGAffineTransformScale(thirdVCView.transform,?0.001,?0.001)
 
????UIView.animateWithDuration(0.5,?animations:?{?()?->?Void? in
 
????????firstVCView.transform?=?CGAffineTransformScale(thirdVCView.transform,?0.001,?0.001)
 
????????})?{?(Finished)?->?Void? in
 
????????????UIView.animateWithDuration(0.5,?animations:?{?()?->?Void? in
????????????????thirdVCView.transform?=?CGAffineTransformIdentity
 
????????????????},?completion:?{?(Finished)?->?Void? in
 
????????????????????firstVCView.transform?=?CGAffineTransformIdentity
????????????????????????????????????????self.sourceViewController.presentViewController(self.destinationViewController?as?UIViewController,?animated:? false ,?completion:?nil)
????????????})
????}
}

自定義轉換準備好了。可是咱們還沒結束,由於咱們必須執行轉場。若是你記得,在ViewController場景裏有個叫「Tap Me!」的button。這是咱們用來啓動轉場的。

首先,打開ViewController.swift文件,添加如下的IBAction方法:

1
2
3
@IBAction?func?showThirdViewController(sender:?AnyObject)?{
????self.performSegueWithIdentifier( "idSecondSegue" ,?sender:?self)
}

如你預期的,咱們只是簡單地執行轉場。注意,轉場的標示符的值必須匹配咱們在Interface Builder裏設置的值。

最後,咱們必須把上面的方法連到按鈕上。打開Main.storyboard.swift文件,在文檔大綱裏的ViewController場景,點在按鈕對象上,而後按住Ctrl和鼠標,拖到ViewController對象上:

t26_35_ibaction_method_connect.png

出現了一個有不少選項的彈出窗口。裏面有個Sent Events,這個下面展現了IBAction方法。選擇它,聯繫就成功完成了。

t26_36_ibaction_method_select.png

若是你想限制你能夠測試這個app。點在最初的視圖控制器的按鈕上,觀察第三個視圖控制器是怎麼呈現的。

第二個解除轉場

在演示app裏咱們實現的第一個解除轉場,我說過你應該作的第一件事是IBAction方法的定義,這個方法在轉場執行的時候被調用。這裏,咱們實現這樣一個方法,叫returnFromSegueActions(sender:),一旦處理好後咱們也將在新的解除轉場中用到它。

上面意味着咱們能夠去作下一個步驟,在Interface Builder中建立解除轉場。打開Main.storyboard文件,在ThirdViewController場景中,選擇ThirdViewController對象,按住Ctrl拖動到Exit對象上。

t26_37_unwind_segue_connect2.png

在彈出框裏點擊操做方法的名字,解除轉場就被建立了。

t26_38_unwind_segue_2_created.png

接下來,選擇那個轉場,打開屬性監視器,在identifier字段裏,設置idSecondSegueUnwind值。

目前解除轉場已經準備好了,咱們能夠寫咱們想要的轉換行爲的代碼。此次,咱們不只僅執行徹底相反的動畫到正常的轉場。咱們將建立一個有點複雜的動畫,第三個視圖控制器的視圖將被縮小,同時移向屏幕頂端,第一個視圖控制器的視圖將被放大,從屏幕底部移動到頂端,因此佔據了整個可用區域。這個視圖最初準備離開屏幕的可視區域。

打開SecondCustomSegueUnwind.swift文件,咱們將最後一次實現perform方法,讓咱們從簡單的開始:

1
2
3
4
5
6
7
override?func?perform()?{
???? var ?firstVCView?=?destinationViewController.view?as?UIView!
???? var ?thirdVCView?=?sourceViewController.view?as?UIView!
 
????let?screenHeight?=?UIScreen.mainScreen().bounds.size.height
 
}

和日常同樣,咱們讓兩個視圖控制器的視圖保存爲局部變量,同時把屏幕的寬和高存儲在一個變量裏。接下來,指定firstVCView視圖的初始狀態。就像我說的,首先定義離屏的位置,這個將按比例縮小:

1
2
3
4
5
6
7
8
9
10
11
override?func?perform()?{
????...
 
????firstVCView.frame?=?CGRectOffset(firstVCView.frame,?0.0,?screenHeight)
????firstVCView.transform?=?CGAffineTransformScale(firstVCView.transform,?0.001,?0.001)
 
 
????let?window?=?UIApplication.sharedApplication().keyWindow
????window?.insertSubview(firstVCView,?aboveSubview:?thirdVCView)
 
}

除了設置初始狀態,咱們也把視圖添加到app的窗口上。

最後,讓咱們執行動畫。記得要消失的視圖按比例縮小,要出現的視圖按比例放大,兩個視圖都往頂部移動。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
override?func?perform()?{
????...
 
????UIView.animateWithDuration(0.5,?animations:?{?()?->?Void? in
 
????????thirdVCView.transform?=?CGAffineTransformScale(thirdVCView.transform,?0.001,?0.001)
????????thirdVCView.frame?=?CGRectOffset(thirdVCView.frame,?0.0,?-screenHeight)
 
????????firstVCView.transform?=?CGAffineTransformIdentity
????????firstVCView.frame?=?CGRectOffset(firstVCView.frame,?0.0,?-screenHeight)
 
????????})?{?(Finished)?->?Void? in
 
????????????self.sourceViewController.dismissViewControllerAnimated( false ,?completion:?nil)
????}
}

這就是自定義解除轉場的實現。接下來是小結性的代碼:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
override?func?perform()?{
???? var ?firstVCView?=?destinationViewController.view?as?UIView!
???? var ?thirdVCView?=?sourceViewController.view?as?UIView!
 
????let?screenHeight?=?UIScreen.mainScreen().bounds.size.height
 
????firstVCView.frame?=?CGRectOffset(firstVCView.frame,?0.0,?screenHeight)
????firstVCView.transform?=?CGAffineTransformScale(firstVCView.transform,?0.001,?0.001)
 
????let?window?=?UIApplication.sharedApplication().keyWindow
????window?.insertSubview(firstVCView,?aboveSubview:?thirdVCView)
 
????UIView.animateWithDuration(0.5,?animations:?{?()?->?Void? in
 
????????thirdVCView.transform?=?CGAffineTransformScale(thirdVCView.transform,?0.001,?0.001)
????????thirdVCView.frame?=?CGRectOffset(thirdVCView.frame,?0.0,?-screenHeight)
 
????????firstVCView.transform?=?CGAffineTransformIdentity
????????firstVCView.frame?=?CGRectOffset(firstVCView.frame,?0.0,?-screenHeight)
 
????????})?{?(Finished)?->?Void? in
 
????????????self.sourceViewController.dismissViewControllerAnimated( false ,?completion:?nil)
????}
}

再次回到ViewController.swift文件,讓咱們看下segueForUnwindingToViewController(toViewController:fromViewController:identifier:) 方法,咱們已經討論過它了,如今咱們必須檢查新的解除轉場,因此咱們初始化,而後返回一個子類的轉場對象。根據咱們以前說的,咱們將再建立一個用例,檢查轉場的標示符是否和解除轉場的匹配,而後再繼續。經過添加以下代碼修改方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
override?func?segueForUnwindingToViewController(toViewController:?UIViewController,?fromViewController:?UIViewController,?identifier:?String?)?->?UIStoryboardSegue?{
???? if ?let?id?=?identifier{
????????...
???????? else ? if ?id?==? "idSecondSegueUnwind" ?{
????????????let?unwindSegue?=?SecondCustomSegueUnwind(identifier:?id,
????????????????source:?fromViewController,
????????????????destination:?toViewController,
????????????????performHandler:?{?()?->?Void? in
 
????????????})
 
???????????? return ?unwindSegue
????????}????????
????}
 
????...
}

這沒有什麼新的或者難的地方。如今新的解除轉場能夠徹底執行了。然而,咱們必須先啓動,經過在第三個視圖控制器裏添加新的向上滑動的手勢來管理它。因此,到ThirdViewController.swift文件,在viewDidLoad文件裏添加以下代碼:

1
2
3
4
5
6
7
override?func?viewDidLoad()?{
????...
 
???? var ?swipeGestureRecognizer:?UISwipeGestureRecognizer?=?UISwipeGestureRecognizer(target:?self,?action:? "showFirstViewController" )
????swipeGestureRecognizer.direction?=?UISwipeGestureRecognizerDirection.Up
????self.view.addGestureRecognizer(swipeGestureRecognizer)
}

咱們只剩下去實現showFirstViewController方法,和其它相似方法同樣簡單:

1
2
3
func?showFirstViewController()?{
????self.performSegueWithIdentifier( "idSecondSegueUnwind" ,?sender:?self)
}

如今,運行這個差很少徹底實現的應用以前,爲何不在第三個視圖控制器消失的時候顯示一條消息呢?

固然能夠。不過,和以前的方法不一樣,咱們在IBAction這個方法returnFromSegueActions(sender:)裏傳遞數據。咱們已經給它添加了一些簡單的代碼,咱們也說了這個方法是隨着解除轉場用來執行各類動做的。

打開ViewController.swift文件,找到上述方法,這裏,添加如下的else代碼:

1
2
3
4
5
6
7
@IBAction?func?returnFromSegueActions(sender:?UIStoryboardSegue){
????...
 
???? else {
????????self.lblMessage.text?=? "Welcome?back!"
????}
}

上面添加的消息將每次顯示到第一個視圖控制器上,第二個解除轉場被執行。

運行應用程序

如今咱們的演示app完成了。你能夠去測試了,固然,若是你想更熟悉自定義轉場你能夠隨意修改任一部分。下面再次展現了app運行的動畫。

final_sample.gif

總結

若是你快速回顧下咱們在教程所作的,你確定會得出這樣的結論:使用自定義轉場並不難。在視圖控制器間應用自定義動畫轉換,能夠有很好的用戶體驗,也使得你的app和其餘的不同凡響。若是自定義轉場對你來講是新的東西,去學習使用他們。我強烈建議你這麼作。咱們實現的演示app能夠指導你以正確的方式實現自定義轉場和解除轉場。咱們建立和應用的動畫並不複雜,但足夠你理解全部的知識點。發揮你的想象力,創造更炫的效果。但願你能喜歡這篇文章,也但願它能派上用場。一如既往的,咱們等待你的想法。

供您參考,您能夠在這裏下載項目。(本文爲CocoaChina組織翻譯,本譯文權利歸譯者全部,未經容許禁止轉載。)

相關文章
相關標籤/搜索