從 storyboard 的 controller 載入 xib 畫面

storyboard 和 xib 有很多共通點,都可以在 Interface Builder 製作畫面,但是如果想讓 storyboard 的 controller 載入 xib 畫面,讓 controller 同時享有 storyboard 拉 segue 和 xib 畫面重覆利用的好處,有可能嗎 ?

當然有呀 ! 接下來,就讓我們實際創作一個情歌 App 示範吧。

1 在 storyboard 設計 App 畫面

我們想要實現以下兩點功能:

  1. 在 storyboard 拉出開心的歌和傷心的歌 controller ,因此可以用 segue 串接畫面。
  2. 開心的歌和傷心的歌將從 xib 載入畫面,因此畫面可以重覆利用。到時候 UI 調整時,只需修改 xib。

2 建立新的 controller SongViewController。

記得勾選 Also create XIB file,如此才會同時建立 xib 檔。

仔細觀察 xib 的 File’s Owner。

(1) 點選 File’s Owner 後,從 Identify Inspector 頁面,可看到它的 Class 被設為 SongViewController。

(2) 選 File’s Owner 後,按右鍵可發現 controller 的 view 連到 xib 的 View 元件。

從以上兩點,我們了解到時候搭配 xib 檔的 controller 物件生成後,畫面將為 xib 裡的 View 元件,而且 controller 的型別為 SongViewController(或是繼承 SongViewController 的類別)。

3 在 SongViewController.xib 裡加上顯示歌名的 label。

4 拉 outlet collection songLabels,方便到時候從程式設定歌名。

5 建立繼承 SongViewController 的 HappySongViewController & SadSongViewController

6 設定開心的歌和傷心的歌

開心的歌

class HappySongViewController: SongViewController {override func viewDidLoad() {   super.viewDidLoad()   songLabels[0].text = "有點甜"   songLabels[1].text = "愛的主旋律"   songLabels[2].text = "戀愛頻率"}

傷心的歌

class SadSongViewController: SongViewController {   override func viewDidLoad() {      super.viewDidLoad()      songLabels[0].text = "街角的祝福"      songLabels[1].text = "小幸運"      songLabels[2].text = "怎樣"}

7 將開心的歌設為 HappySongViewController,傷心的歌設為 SadSongViewController。

7 在 SongViewController 裡覆寫 loadView,利用 loadNibNamed(_:owner:options:) 載入 SongViewController.xib 的畫面。

class SongViewController: UIViewController {   @IBOutlet var songLabels: [UILabel]!   override func loadView() {      super.loadView()      Bundle.main.loadNibNamed("SongViewController", owner: self, options: nil)}

在 SongViewController.xib 裡,File’s Owner 的類別是 SongViewController,它代表 SongViewController 或繼承 SongViewController 的類別建立的物件都可以當 File’s Owner。

當 App 顯示開心的歌時,controller 的型別為 HappySongViewController。當 loadView 執行,呼叫 loadNibNamed(_:owner:options:) 時,傳入當 owner 的 self 型別正是 HappySongViewController。此時它會把 controller 的 view 換成 xib 的 view,取代原本 storyboard 裡的 view。至於傷心的歌,也是類似的道理,到時候 owner 的型別將為 SadSongViewController。

最後,為了避免打錯字,xib 的名字也可以用 String(describing: SongViewController.self) 生成,以自動完成的方式輸入。

Bundle.main.loadNibNamed(String(describing: SongViewController.self), owner: self, options: nil)

結果

--

--

彼得潘的 iOS App Neverland
彼得潘的 Swift iOS App 開發問題解答集

彼得潘的iOS App程式設計入門,文組生的iOS App程式設計入門講師,彼得潘的 Swift 程式設計入門,App程式設計入門作者,http://apppeterpan.strikingly.com