iT邦幫忙

2021 iThome 鐵人賽

DAY 2
0
Mobile Development

在 iOS 開發路上的大小事系列 第 2

【在 iOS 開發路上的大小事-Day02】拋棄 Storyboard 改用 Xib 來做全部的 UI 設計吧

前情提要

一般在用 Xcode 創新專案的時候,會預設使用 Main.storyboard 來作為我們設計 UI 畫面的地方

但這樣有個缺點,就是當你 Storyboard 上面有很多畫面的時候,Storyboard 會需要比較長的時間載入,以及在開發上如果要對某個畫面做動作時,有時候會很難處理,讓開發效率降低
所以通常會建議改用 Xib 來做 UI 畫面設計,這樣每個畫面、每個元件都會是一個檔案
在開發上會比較好處理,開發效率也會比較高
但沒有說用 Storyboard 做 UI 畫面設計就不好,還是要依實際狀況來做變通~

實際操作

首先先到專案設置的檔案 (檔名:專案名稱.xcodeproj),找到「Deployment Info」

找到「Main Interface」,然後將他清空

再切到「Info.plist」,找到「Application Scene Manifest」,將其全部選項都點開
全部點開後,會看到「Storyboard Name」這一行,然後把它整行刪掉,如下圖

接著,再將左側的專案檔案列表裡面的「ViewController.swift、Main.storyboard」這兩個檔案刪掉

接著先建立一個資料夾,來放第一個畫面的檔案,我們取名為「MainVC」,然後在裡面新增名為「MainVC.swift、MainVC.xib」的檔案

把「Also create XIB file」打勾,就會自動產生這個 ViewController 的 xib 檔案,來讓我們進行 UI 畫面設計,現在我們左側的專案檔案列表應該會長這樣

接下來,終於要來寫 Code 了~
如果你的 App 最低的系統安裝版本是 iOS 13 以前的話,像是 iOS 12、iOS 11 之類的
那你要在「AppDelegate.swift 跟 SceneDelegate.swift」這兩個檔案加入下方的 Code
如果如果你的 App 最低的系統安裝版本是 iOS 13 (含)以上的話
那就直接在「SceneDelegate.swift」這個檔案加入下方的 Code

會有這樣的區別是因為 SceneDelegate.swift 是只有 iOS 13 (含)以上版本才會去讀這個檔案,iOS 13 以下的版本則是會去讀 AppDelegate.swift 這個檔案

所以說,如果你要讓 App 可以順利在 iOS 13 以前跟以後的系統都可以順利開啟的話,就要在 AppDelegate.swift 跟 SceneDelegate.swift 這兩個檔案裡都加入下方的程式碼

App 最低的系統安裝版本是 iOS 13 以前的話,像是 iOS 12、iOS 11 之類的↓

// AppDelegate.swift
class AppDelegate: UIResponder, UIApplicationDelegate {
    var window: UIWindow?
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        let rootVC = MainVC(nibName: "MainVC", bundle: nil)
        window = UIWindow(frame: UIScreen.main.bounds)
        window?.rootViewController = rootVC
        window?.makeKeyAndVisible()
        return true
    }
    ...
}
// SceneDelegate.swift
@available(iOS 13.0, *) // 這行加在 class 上面
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
    var window: UIWindow?
    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        guard let windowScene = (scene as? UIWindowScene) else { return }
        let rootVC = MainVC(nibName: "MainVC", bundle: nil)
        let navigationController = UINavigationController(rootViewController: rootVC)
        window = UIWindow(frame: windowScene.coordinateSpace.bounds)
        window?.windowScene = windowScene
        window?.rootViewController = navigationController
        window?.makeKeyAndVisible()
    }
    ...
}

App 最低的系統安裝版本是 iOS 13 (含)以上的話↓

class SceneDelegate: UIResponder, UIWindowSceneDelegate {
    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        guard let windowScene = (scene as? UIWindowScene) else { return }
        let rootVC = MainVC(nibName: "MainVC", bundle: nil)
        let navigationController = UINavigationController(rootViewController: rootVC)
        window = UIWindow(frame: windowScene.coordinateSpace.bounds)
        window?.windowScene = windowScene
        window?.rootViewController = navigationController
        window?.makeKeyAndVisible()
    }
    ...
}

成果


本篇的範例程式碼:GitHub


上一篇
【在 iOS 開發路上的大小事-Day01】先裝個 Xcode 開發環境壓壓驚
下一篇
【在 iOS 開發路上的大小事-Day03】透過 Global Variable 來傳值
系列文
在 iOS 開發路上的大小事30

尚未有邦友留言

立即登入留言