寫在前面
我不算是個資深碼農,有些iOS的編程經驗。希望找到一種高效的方式來創作出自己的iOS應用。大家都知道純代碼寫應用的成本是很高的,特別是涉及到UI界面的實現,相當耗費時間。之前自己寫應用時有了解過Storyboard,也簡單使用過,但隨著最近深入了解它之后,發現自己低估了它的作用和影響力,因此在這里總結下最近段時間學習到的內容,希望對Storyboard初學者有所幫助。Interface Builder的界面布局如下圖:
(圖片來自Apple官網)
1.基礎概念
在學習Storyboard的使用,有三個概念是最容易混淆的:xib、nib、storyboard。
- xib:是一個可視化文件,可通過拖拽文件進行界面創作和布局。xib實際是個xml文件,xib = XML nib。
- nib:xib編譯之后就得到nib文件,nib= NeXT Interface Builder
- storyboard:大家可以理解為是升級版的xib,可以同時管理多個xib文件并處理場景與場景之間的跳轉。
2.拖放元素
在storyboard/xib上通過拖放對象到界面上就能實現界面元素的創建,與純代碼UI相比可以節省很多調試的時間,所見即所得是高效的重要方式。
(圖片來自Apple官網)
拖放元素后,可以通過Attributes Inspector上的各種滑塊、調色板、大小設定等方式來進行元素屬性的配置(注意只支持大部分,而不是所有。沒有提供的屬性可通過User Defined Runtime Attributes來進行設置)
3.連線——IBOutlet和IBAction
在Storyboard/xib上通過拖放對象來完成界面布局后,我們就得到一個靜態的界面,那接下來應該怎么把這些界面元素與代碼關聯起來,秘密就在于“連線”。
把storyboard上的界面對象與代碼關聯起來,我們俗稱為連線。因為在xcode上的操作就是拖出一條線來把它們進行關聯。
進行連線有兩種方法:
- 選中某個界面元素,按下Control后拖出線條來進行關聯。
- 選中某個界面元素,切換到Connections Inspector界面,在每項后面的圓圈拖出線條來進行關聯。
IBOutlet
第一種連線是IBOutlet,它的作用是把靜態的界面元素與代碼進行關聯,使得代碼中的變量與界面元素對應起來。關聯之后就可通過代碼對界面元素屬性進行操作,如更換背景顏色,增加描邊之類的。
(圖片來自Apple官網)
IBAction
第二種連線是IBAction,它的作用是把界面元素的事件與代碼中的方法關聯起來,當用戶對元素觸發了某個事件之后,讓系統執行特定的代碼對用戶的操作進行響應。例如按鈕被按下后,會執行跳轉到另外一個界面的代碼。
(圖片來自Apple官網)
4.File’s Owner
看到這里,大家可能有個疑問:xcode怎么知道浙西界面要與哪個文件(類)進行聯系,以進行接下來的連線操作?答案在于File’s Owner。
File’s Owner描述了xib文件的擁有者是誰(這也是字面的意思),決定了界面元素可以與哪些文件的變量進行IBOutlet,決定了界面的事件可以與哪些文件的方法進行IBAciton。
設置File’s Owner:在Xib文件(注意不是storyboard),選中File’s Owner通過Identity Inspector中設置xib的Class來起對指定應的擁有者。
- 基于VC創建的xib,默認已經設置好對應的File Owner,所以一般無需自己設置,如果特殊情況可以指定其他的文件作為其擁有者。
- 而基于View創建的xib,一般要指定對應的File’s Owner。
注意:在storyboard已經沒有file’s owner這個概念,但并不妨礙連線。每個VC上有三個按鈕,連線時只要拖線到第一個按鈕即可進行關聯。
5.Storyboard VS Xib
storyboard和xib在界面和操作上大體相同,這里聊下它們之間的差別(歡迎進行補充)
- storyboard的文件以.storyboard結尾,xib文件以.xib結尾
- storyboard更注重于多個場景(頁面)的層級關系及跳轉,而xib更注重于單個頁面的布局和復用性,這可以作為選擇使用storyboard還是xib的參考。
- storyboard上只能使用VC,不能單獨使用UIview,UIView只能基于VC上進行使用,而xib同時支持兩者。這一點也印證了上面提到的兩者的不同傾向。
- storyboard上沒有file’s Owner的概念,默認通過VC的class的指定其擁有者。
- storyboard上可以通過segue實現無需代碼的界面跳轉,而xib由于管理的是單個界面,因此只能通過代碼來實現界面的切換。
6.頁面切換Segue
Segue的出現,讓無需代碼進行頁面切換成為可能,這是工作高效的第二個很重要的技能,只需要簡單的設置幾下技能實現之前通過代碼實現的跳轉,相當贊!Segue實際是UIStoryboardSegue對象。
通過segue可以實現:
- 從一個頁面切換到另外一個頁面
- 通過unwind Segue回退到某個頁面
- 實現傳參數
- 可以指定跳轉到具體的頁面,也可以進行不確定的頁面跳轉(實際上是通過代碼來控制要跳轉的目標頁面)
跳轉到一個指定的頁面
一般情況下,用戶觸發了界面上的某個元素進行特定操作后,應用執行界面的跳轉。
具體操作:在Storyboard的VC上,選中觸發跳轉的元素,按Control拖線條到目標的VC,之后在出現的Action Segue菜單中選則切換方式,成功設置segue后,在兩個VC間就會出現連起來的線。就這么簡單!是不是很實用。
(圖片來自Apple官網)
注意觀:不同類型的Segue會對應不同的圖標,見下圖:
unwind Segue實現頁面回退
之前大部分情況下是通過代理來實現頁面間的回退,例如要取消一個模態視圖,需調用dismissViewControllerAnimation()的方法?,F在可以通過Unwind Segue更簡單方便的實現這樣的回退,這又是個高效的技能。
具體步驟如下:
- 在回退的目標頁面上提供回退處理方法。例如從VC2返回到VC1,那么回退的方法應該寫在VC1上。
- 定義回退方法?;赝朔椒ǖ?strong>返回值必須是IBAciton,并帶上UIStoryboardSegue參數。例如:
@IBAction func close (segue:UIStoryboardSegue)。
該方法方法只需要定義,不需要方法體。
- 關聯。在VC2觸發返回操作的元素上按control鍵拖線到Exit圖標(每個VC上方三個圖標中的第三個),在出來的Action Segue菜單中選剛才定義好的回退方法close()。這樣就可以實現頁面的回退。
segue傳參
有時在頁面跳轉的時候,需要把參數傳到新的頁面,使用Segue實現頁面跳轉時應該怎么實現這一點?
在跳轉即將發生時會調用prepareForSegue:,因此可以在這個方法上做文章。示例代碼:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier=="goToB"{
let bVC = segue.destinationViewController
bVC.testTite = @"hello world"
}
}
segue對象有個destinationViewController的屬性可以獲取跳轉到的目標VC,這樣就可以在跳轉之前把當前VC的值賦予目標VC的某個屬性,從而實現參數的傳遞。
順便提一下,當segue不止一個的時候就需要給它進行標識,以便在處理跳轉的過程中進行定制化,就像上面的代碼,當判斷segue的標識為goToB的時候才進行下面的操作。設定標識符的方法很簡單,選中segue連線,在attribute inspector中設置identifier就可以了。
segue配合代碼進行不確定的頁面跳轉
有時會出現這樣的情況,我們確定從A頁面會跳轉到B、C、D頁面,但具體跳轉到哪個頁面是需要通過邏輯觸發的。這種情況應該如何用Segue來實現?
- 在.storyboard文件的導航視圖中找到起始VC,右鍵菜單找到Triggered Segues下的manual后面的+,拖線到可能要跳轉到的VC。
- 給Segue設置標識。
- 代碼實現Segue跳轉。在觸發的事件響應方法IBAciton中嵌入跳轉頁面的代碼。如點擊按鈕之后,通過邏輯判斷跳轉到不同的頁面。這時候,就可以在按鈕的按下事件的響應方法上嵌入下面的跳轉代碼。
self.performSegue(withIdentifier: "id", sender: sender)
- 這樣就實現了通過segue設置頁面的跳轉關系,通過代碼來控制具體的目標頁面,從而實現不確定的頁面跳轉。
以下內容與界面適配有關,發現網絡上已經有比我自己總結更好的文章,因此就不在這里搬磚了。大家可以參考外鏈來學習。
7.屏幕大小適配
在xcode8之前,為了在一個Storyboard中適配不同的屏幕大小,需要使用相對抽象的概念——Size Class。但xcode8之后你可以直接選擇不同設備查看對應界面布局,甚至進行界面元素的差異化。這樣比理解Size Class概念更為人性化。
有興趣了解Size Class的可參考這篇文章:初探 iOS8 中的 Size Class
8.AutoLayout
單靠Size Class無法解決適配問題,真正起作用的是AutoLayout,它為我們處理同一個屏幕尺寸下不同旋轉方向上的的界面布局提供簡單可行的方案。
用Apple官方的說法來描述:
AutoLayout是一種基于約束的,描述性的布局系統。 Auto Layout Is a Constraint-Based, Descriptive Layout System.
AutoLayout的位置是使用相對位置的約束來定義的,簡單來說就是通過與B的相對距離來定義A的位置。這樣,不管屏幕的旋轉情況如何,我只要告訴你這個元素相對于屏幕邊緣的距離就可以定義元素的位置。這樣比逐個處理屏幕的旋轉情況來得更加高效。
具體介紹可參考:WWDC 2012 Session筆記——AutoLayout(自動布局)入門
9.來點新玩意
IBInspectable
@IBInspectable是xcode6之后才出現的,用來修飾屬性,使得自己定義的屬性可以出現在interface builder的界面上,進行可視化編程。
@property(nonatomic,assign) IBInspectable CGFloat cornerRadius;
定義后,在storyboard查看對應VC的Attributes Inspector就會神奇的發現多了一個可設置的屬性。
IBDesignable
@IBdesignable也是Xcode6之后才引入的,主要作用是,可以在不運行的情況下,就能把代碼效果顯示在Storyboard/Xib上。
不過有幾點要注意的:
- @IBDesignable需寫在Class前面。
- 要想IBDesignable起作用必須把代碼寫在drawRecr方法中才能顯示出來。
更多IBInspectable和IBDesignable的介紹,可戳這里。
總結
最后再次強調下幾個提高產出效率的點:
- 在storyboard/Xib進行UI界面的布局。
- 通過Segue來是實現頁面間的跳轉。
- 通過AutoLayou來適配不同的屏幕尺寸和旋轉方向。
另外貼個 Xcode的官方介紹文檔 ,可更深入的了解Xcode的使用。
(如發現內容出現紕漏,望各位大牛指正。如有補充,歡迎留言,謝謝。)