建立一個像Medium App的下滑選單

導覽(Navigation)是使用者介面其中一個很重要的部分。有好幾種讓使用者透過選單來存取App功能的方式。我們經常見到的側邊選單就是其中一例。下滑選單也是另外一種常見的選單設計。


當一個使用者按下選單按鈕,主畫面下滑揭示了選單。如下圖是在Medium App中使用到下滑選單的畫面。

slide-down-menu-sample

倘若你前面的章節有跟著一起進行,你應該對客製視圖控制器轉換有了基本的了解。本章,你將運用你所學到的來建造一個生動的下滑選單。

依照慣例,我想你不需要從頭建立專案,建議可以使用我們準備好的範例模板來開始,它包含了Storyboard 以及視圖控制器類別。你將會發現兩個視圖控制器。一個是主畫面(嵌入至導覽控制器中),而另一個導覽選單。倘若你執行專案,這個App應該會出現一個主畫面加上一些虛構的資料。 繼續往下進行之前,先花個幾分鐘瀏覽一下這個程式模板以熟悉一下專案內容。

以Modal 方式呈現選單

好的,我們開始吧。首先打開 Main.storyboard檔。你應該會找到兩個還沒有連上任何Segue的表格視圖控制器,為了在使用者按下選單按鈕時能帶出選單,按住control鍵不放,從選單按鈕拖曳至選單表格視圖控制器(menu table view controller)。將按鈕釋放,然後選取「present modally」作為Segue的動作。

slide-down-menu-segue

倘若你執行專案,這個選單將會以modal視圖的方式來呈現。為了關閉(unwind)選單,我們會加入unwind Segue。

打開NewsTableViewController.swift 檔並插入一個unwind動作方法:

現在回到Storyboard,按住control 鍵不放,從Menu table view controller的prototype cell 拖曳至exit 圖示。提示出現之後,在selection segue選擇unwindToHome: 選項。

slide-down-menu-unwind

現在當使用者按下任何選單項目,選單控制器便會解除,進而揭示主畫面。透過 unwindToHome: 動作方法,這個主視圖控制器(也就是NewsTableViewController)依照使用者在選單項目上的選取來變更其標題。為了簡單起見,我們只是變更導覽欄(navigation bar)的標題,而不會改變主畫面的內容。

另外,主視圖控制器會將所選取的項目以白色來標示,想讓App能如預期般順利運作前,還有幾個方法要先實作。

MenuTableViewController 類別插入以下的方法:

這裏我們只是設定 currentItem 為選單選取的項目。

在NewsTableViewController.swift 檔,插入下面的方法來傳遞目前的標題至選單控制器:

現在編譯與執行專案。按下選單項目,App便會以modal方式來呈現選單,當你選取選單項目,選單會關閉,導覽欄標題也會跟著變更。

slide-down-menu-1

建立生動的下滑選單

現在選單是使用標準動畫來呈現,我們來建立自訂轉換。如同我前面章節所述,客製視圖控制器動畫的核心,是動畫物件遵循了UIViewControllerAnimatedTransitioningUIViewControllerTransitioningDelegate 協定。我們準備實作這個類別。但是我們先來看下滑選單的運作方式。當使用者按下選單,主視圖開始下滑直到它到達預定的位置,也就是離畫面底部150點處。以下的圖片說明可以讓你對滑動選單更有概念。

slide-down-menu-explained

建立下滑選單動畫

想要建立下滑特效,我們會建立一個稱作MenuTransitionManager 的下滑動畫。在專案導覽器,按右鍵來建立一個新檔案。將類別取作MenuTransitionManager,並將其設為NSObject的子類別。

更新類別如下:

這個類別實作UIViewControllerAnimatedTransitioningUIViewControllerTransitioningDelegate 協定。我不準備解釋這個方法的細節,因為前面章節已經解釋過了。我們將重點放在動畫block(也就是animateTransition 方法)。
參考前面圖片說明,在轉換期間主視圖是 fromView,此時選單視圖是toView

要建立動畫,我們設置兩個變換。第一個變換(也就是 moveDown)是用來下移主視圖。第二個變換(也就是 moveUp)是設定將選單視圖上移一點,所以當它回復到原來位置時,它會有下滑效果。稍後你執行專案,你將會瞭解我的意思。

從iOS 7 開始,你可以使用UIView-Snapshotting API 來快速且輕易的建立一個輕量級(light-weight)的視圖快照(snapshot)。

透過snapshotViewAfterScreenUpdates方法的呼叫,你有一個主視圖的快照。有了快照,我們可以將其加入容器視圖來執行動畫。注意這個快照是加到選單視圖的上方。

選單呈現的實際動畫,其實作是非常簡單的。我們只是對主視圖的快照實施moveDown 變換,並將選單視圖回復其預設位置。

當選單解除時,逆向效果便開始發生。主視圖的快照向上滑動並回到其預設位置。另外快照會從它的父視圖被移除,也因此我們可以將實際主視圖帶回。

現在打開NewsTableViewController.swift 並宣告一個變數給MenuTransitionManager 物件:

prepareForSegue 方法,加上一行變數來串接動畫:

就這樣!你現在可以編譯與執行專案。按下選單按鈕,你將會得到一個下滑選單。

slide-down-menu-output2

偵測按下手勢

現在唯一關掉選單的方式就是選取選單項目。從使用者的觀點,按下快照應該也要能關掉選單。不過,主視圖的快照沒有反應。

這個快照實際上是一個UIView物件。因此我們可以建立一個UITapGestureRecognizer 物件並將其加至快照。

實體化一個UITapGestureRecognizer物件,我們需要傳給它一個目標物件(target object),也就是接收由接收者所發送的動作訊息,且會呼叫動作方法。

很明顯地,你可以將特定物件寫進去,作為目標物件來解除視圖。但是為了讓設計有所彈性,我們會定義一個協定讓代理物件來執行它。

在MenuTransitionManager.swift,定義下面的協定:

這裏我們以必要實作做的方法來定義一個MenuTransitionManagerDelegate 協定。這個代理應該要實作「dismiss」方法,並提供解除或關閉視圖的實際邏輯。

註:這裏的協定必須要公開為使用Objective-C運行 ,因為它會被UITapGestureRecognizer 存取。這也是為何協定的字首要加上 @obj的原因。

MenuTransitionManager 類別,宣告代理變數:

稍後要負責處理按下手勢的物件,應該設為代理物件。

最後,我們需要建立一個UITapGestureRecognizer 物件並將其加入快照中。一個比較好的方式是在snapshot變數中定義一個 didSet 方法。變更snapshot宣告如下:

屬性觀察者(Property observer)是Swift中一個強大的功能。每次屬性的值設定後會呼叫觀察者(willSet/didSet)。這提供了在指派之前或之後,立即執行某個動作的便利方式。willSet 方法在值被儲存前會被呼叫,而 didSet方法在指派後會立即呼叫。

在以上的程式中,我們使用屬性觀察者來建立一個手勢辨識器(gesture recognizer)並設定給快照。所以在每次指派一個物件給snapshot變數時,它會立即設置按下手勢辨識器(tap gesture recognizer)。

我們幾乎已經完成了。現在回到NewsTableViewController.swift,也就是要實作MenuTransitionManagerDelegate 協定的類別。

首先,變更類別宣告如下:

接下來,實作協定所需的方法:

這裏我們只是透過dismissViewControllerAnimated 方法的呼叫來解除視圖控制器。

最後,在NewsTableViewController類別的prepareForSegue 方法中插入下面一行程式,來設定它自己為代理物件:

很棒!你已經準備好再次測試App了,按下Run按鈕來測試。你應該能夠在按下主視圖的快照後解除選單。

如果將自訂的視圖控制器轉換運用得宜,它能夠很棒的改善使用者體驗,讓你的App與眾不同。下滑選單只是一個例子。試著在你的下一個建立你自己的動畫。

為了進一步讓您參考,你可以在這裡下載完整的 Xcode 專案

譯者簡介:王豪勳 -渥合數位服務創辦人,畢業於台灣大學應用力學研究所,曾在半導體產業服務多年,近年來專注於協助客戶進行App軟體以及網站開發,平常致力於研究各式最軟硬體技術,擁有多本譯作。

本文摘自提升iOS 8 App程式設計進階實力的30項關鍵技巧。如有興趣了解其他技巧,可到博客來天瓏購買此書。


軟件工程師,AppCoda 創辦人。著有《iOS 9 App 程式設計實力超進化實戰攻略》,《養成iOS 8 App程式設計實力的25堂課》,以及《iOS 8 App程式設計進階實力的30項關鍵技巧》。曾任職於HSBC, FedEx等公司,專責軟體開發、系統設計。2012年創立AppCoda技術部落格,定期發表iOS程式教學文章。現時專注發展AppCoda,致力於iOS程式教學,產品設計及開發。

blog comments powered by Disqus
訂閲電子報

訂閲電子報

AppCoda致力於發佈優質iOS程式教學,你不必每天上站,輸入你的電子郵件地址訂閱網站的最新教學文章。每當有新文章發佈,我們會使用電子郵件通知你。

已收你的指示。請你檢查你的電郵,我們已寄出一封認證信,點擊信中鏈結才算完成訂閱。

Shares
Share This