本文由CocoaChina翻譯小組成員Lollypo(社區ID)翻譯自David McGraw
原文:10 Practical Tips for iOS Developers Using Storyboards
在這裡我將著重講述10件事情,而不會去全面講述如何使用Storyboard去創建一些事物。這些知識點沒有特定的順序,但它們也許可以幫到你在這條道路上前行。
Storyboard是我花時間鑽研最多的一個領域。我非常喜歡可視化編程。只需要簡單地將項目拖到畫布中,更新位置信息,再設置一些描述信息,就已創建了一個用戶界面而不用編寫任何代碼。這非常重要,因為用戶界面的代碼可以很快讓你的代碼變得一團糟。
當我參與到一個新的項目時,我首先要做的就是找到其中的Storyboard。這是概覽程序整體框架的一處重要之地。
假如沒有使用可視化編輯器,你就需要手動化操作才能發現工作的進展。你在代碼中來回往復耗費大量時間,也只能大致了解給定的視圖的情況。您可以明確參考設計文件或運行應用程序並導航到所需的區域,但我更希望避免這種情況。最後,在某些情況下,調整界面組件成為一個繁瑣的過程。你不斷編譯並運行應用程序去驗證它們是否都在正確地位置,而不是通過Storyboard快速調整。
看看,只是創建右邊這麼一個簡單的界面就編寫了這麼多的代碼,我甚至還沒有編寫任何自動布局代碼來幫助我們定位。我知道會有頑固的代碼狂人。但我還是不想這些讓我的代碼膨脹,這實在是讓人不快。不要誤會我。對於初學者來說,這樣做的價值是理解如何通過代碼創建一個用戶界面。通過一個給定的用戶界面,你有了一個大概的認識,知道它能做什麼。而不是查閱文檔。
列表
也許可以歸為一件,不過不用在意
你不需要將整個程序搭建在一個故事板中。可以將它們分成好幾個故事板。假設有管理面板,設置面板,以及主面板。當你的程序擴大後可以節省你的很多精力。在團隊中工作時與故事板交互也會變得輕松,而且查找需要的故事板也會更快捷。
什麼是exit segue,如何使用它
首先,我說一下什麼是segue。假設你現在的故事板中有兩個場景,其中第一個場景中有一個按鈕。當你右擊場景1的按鈕,然後拖動到場景2,你這樣就是創建了一個segue。
現在假設我們選擇present modally。該模態表示這是用戶優先關注的場景。這沒有簡單的方法來回到第一個場景,就像你可能看過的如果你推送一個場景到導航棧上。我們可以創建一個委托來通知第一個控制器我們已經完成。但這樣有些乏味,我們也可以發送通知給第一個控制器,但這就是有點大材小用。這是一個機會使用exit segue,exit segue就像segue一樣工作,不同的是會返回到執行UIStoryboardSegue動作的地方。這就是關鍵!
通過你創建的segue,exit segue可以一直後退導航,無論segue是在那創建的,都可以找到exit segue。
查看一下下方的完整地視圖結構。
如果你只是右擊按鈕的exit segue指示器,你不會看到任何東西。它需要檢測你在目標控制器中創建一個UIStoryboardSegue動作的方法(綠色箭頭指向)。例如:
@IBAction func unwindToSceneA(unwindSegue: UIStoryboardSegue) { // be sure to give your unwind segue an identifier so you know where we're coming from }
Storyboard(故事板)跳轉
你無需在故事板中繪制漂亮的segue到你想去的地方。你只需初始化故事板以及獲取你想要展示的控制器。一旦你有了控制器,你可以調用必要的顯示方法。
var storyboard: UIStoryboard = UIStoryboard(name: "Settings", bundle: nil) var modal: UIViewController = storyboard.instantiateViewControllerWithIdentifier("settingsStoryboardId") as UIViewController self.presentViewController(modal, animated: true, completion: nil) /* If you're fetching a controller in the same storyboard you're already on, * then you can skip initializing a new UIStoryboard object. */ var modal: UIViewController = self.storyboard?.instantiateViewControllerWithIdentifier("customStoryboardId") as UIViewController self.presentViewController(modal, animated: true, completion: nil)
預覽編輯器
如果花所有時間去構建並運行應用程序以觀察用戶界面是否調整到你想要的結果,是很乏味的。在處理自動布局時尤其如此。
現在打開預覽編輯器,你可以修改視圖,觀察它如何變化。你也可以按下左下角助理編輯面板上的+按鈕,以便在多個屏幕尺寸預覽界面。
讓手指休息一下
如果你有一個按鈕需要連接到源代碼中,你可以右鍵單擊,然後拖一條線到源文件中為你生成一個outlet.
此外,對於一個給定的事件,你可以通過單擊再拖到你的源文件來生成一個action。
以上操作的最終結果。
那,為什麼需要做這些操作呢? 這麼說吧,最明顯的就是action。如果你不創建一個@IBAction函數,那麼當你按下按鈕的時候不會有任何事情發生。你可以假設需要添加一些代碼來改變UIImageView中最初設置的的圖片。為了改變這個圖片我們就需要一個@IBOutlet以便我們訪問它。
避免極其復雜的控制器
盡管你的控制器可以管理大量子視圖,但你的風險在於一層一層的添加視圖,這會使事情完全被破壞。很快你就會發現,你偏離了使用可視化編輯器的目的--提供清晰的視圖層次。如果你有一個復雜的視圖結構,那麼是時候考慮這些設置。
你可以使用一個xib,或者你可以添加一個容器視圖對象到你的場景,並隱藏它直到需要的時候。通常我使用xib,但在某些情況下則使用容器視圖對象。
當你添加一個xib的同時還會添加一個源文件,你將使用它來初始化xib.例如,我們創建了ExampleView.xib以及一個漂亮的場景。為了加載這個視圖我們需要創建ExampleView.swift以及初始化這個xib。
import UIKit class ExampleView: UIView { // normal initialization override init(frame: CGRect) { super.init(frame: frame) self.addExampleViewSubview() } // will be loaded if we use this class in a storyboard, for example required init(coder aDecoder: NSCoder) { super.init(coder: aDecoder) self.addExampleViewSubview() } func addExampleViewSubview() { var xib = NSBundle.mainBundle().loadNibNamed("ExampleView", owner: self, options: nil) var view: UIView = xib.first as UIView view.frame = self.frame self.addSubview(view) } }
占位符約束
這是給那些喜歡混合使用代碼與故事板操縱約束的人的。即使我個人盡可能地避免在代碼中編寫約束,但這對於那些不屬於故事板的視圖確實是很有作用的。
假如你試圖在代碼中創建約束,且需要與故事板中的用戶界面交互,這可能會是一個非常可怕的經歷。不過不要害怕,你可以很輕松地告訴Xcode這個特定約束是一個占位符。這意味著在構建和運行應用程序時它將被忽略。
默認的試圖控制器
你可能需要更改哪個場景與故事板一起加載。在早期版本的Xcode中你也許會選擇一個場景,然後選擇**Is Initial View Controller**。在Xcode的最新版本變了。現在你需要搜索對象庫,找到 **Storyboard Entry Point**,然後你可以拖拽到想要的場景。這其中一次只能有一個是活躍的,所以你可以可以拖拽它到你想想要的任一控制器中。
為什麼你會擔心入口點發生改變?就我個人而言,我使用它來測試不同的控制器,我不想創建大量的按鈕才能進到控制器裡去。如果你只是更新故事板的入口點,它就會立即加載。
自定義Segue轉場效果
如果你選中一個segue,你可能已經注意到,它有一些預加載的轉場效果,比如垂直覆蓋、水平翻轉、淡入淡出以及部分卷曲等。如果你想要更多的自定義效果呢?在這種情況下你需要創建一個自定義UIStoryboardSegue。
舉個簡單的粟子,創建一個新的Swift文件,取名為**CustomSegue**。 當我們的segue被執行的時候(上面的按鈕被點擊),下面這段代碼也會被執行。
import UIKit class CustomSegue: UIStoryboardSegue { var startingPoint: CGPoint = CGPoint(x: 0, y: 0) override func perform() { var source = self.sourceViewController as UIViewController var destination = self.destinationViewController as UIViewController // Add the destination view as a subview (temporarily) source.view?.addSubview(destination.view) // Set the start scale destination.view.transform = CGAffineTransformMakeScale(0.05, 0.05) // Original center point var originalCenter = destination.view.center destination.view.center = self.startingPoint UIView.animateWithDuration(0.225, delay: 0.0, options: UIViewAnimationOptions.CurveEaseOut, animations: { () -> Void in destination.view.transform = CGAffineTransformMakeScale(1.0, 1.0) destination.view.center = originalCenter }) { (finished) -> Void in destination.view.removeFromSuperview() source.presentViewController(destination, animated:false, completion:nil) } } }
按下鈕按時,這將從我們設置的一個起始位置展開目標視圖。在這種情況下,我設置起始位置為場景1中按鈕的中心位置(源場景)。
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { let custom = segue as CustomSegue custom.startingPoint = self.nextImage.center }
在故事板文件中我們選擇從場景1到場景2的segue。更改Segue為Custom,然後輸入Segue類來匹配我們剛剛創建的一個CustomSegue。
避免源代碼管理的噩夢
對於那些在團隊中的人來說,雖然他們也在逐漸變得更好,但當涉及到源代碼管理時,故事板仍是一個大痛處。這也是為什麼你應該將故事板拆分成若干個。如果你可以避免這個,請確保同一時刻只有一個人操作故事板。這會避免其他人提交故事板的更改到項目中產生的沖突。即使這並不那麼容易去避免,但請做好准備防止這種情況出現。這也許是團隊與小公司不想使用故事板最大的原因。
盡管當我與的團隊共享故事板時很有可能會導致源代碼控制的沖突,我仍然覺得,速度和效益的重要性大於修補因為沖突導致的惱人補丁。在大多數情況下我確保其他人避免與我同時處理。但是,它仍然一次又一次發生。
這裡是我如何處理沖突的方法:
(第一道防線)首先主動避免它。在與故事板工作時我經常盡早的提交,並且對其他也在與這個故事板工作的人打個招呼。當與其他人一起工作時,盡量保持小任務量的工作,以及互相幫助。不要推送整體的大更新。
如果我遇到了沖突,我會通過差異工具[Kaleidoscope](http://www。kaleidoscopeapp。com/)來浏覽。這確實需要一些經驗來理解故事板的原理。如果你還沒看過,現在就是時候。右鍵點擊 storyboard > open as > source code,觀察控制器區域(包括連接信息)是如何陳列布局的。
(糟糕的情況)我找出了誰做的最大的更改,誰接收的這些變化信息,覆蓋其了其他什麼,然後我們會恢復這些改變。
我做過一些大型的項目。雖然這些合並的issues不是經常嚴重到diff工具不能恢復。但你可以獲得更多的經驗。
我不能強調第一點是足夠的。積極主動很重要。知道你的團隊是什麼樣地情況。如果你有一個令人難以置信的復雜的故事板,就將它板劃分成不同的區域。
拿走不謝
故事板是非常有用的,尤其是對於那些非常直觀的東西。當做原型時,也可以給你一個不錯的速度優勢。無需為代碼煩憂,你可以快速將各種元素放在適當的地方,連接它們,然後從驅動界面的邏輯開始做起。