SwiftUI 框架

為 UIKit 視圖構建 SwiftUI PreviewProvider 實時預覽 UI 的更改!

在 SwiftUI 設計時,我們隨時都可以在 PreviewProvider 查看更改。但在 UIKit 視圖,我們就每次都需要重新編譯和構建專案,才能在模擬器中看到結果。在這篇文章中,Emad 會教大家在 UIKit 構建 SwiftUI 的 PreviewProvider,讓我們可以在 UIKit 實時預覽更改!
為 UIKit 視圖構建 SwiftUI PreviewProvider 實時預覽 UI 的更改!
為 UIKit 視圖構建 SwiftUI PreviewProvider 實時預覽 UI 的更改!
In: SwiftUI 框架, UIKit
本篇原文(標題:Build a SwiftUI PreviewProvider for UIKit Views)刊登於作者 Medium,由 Emad Beyrami 所著,並授權翻譯及轉載。

你有沒有試過使用 SwiftUI?是不是也覺得 SwiftUI 非常易於使用?

在 UIKit 視圖中,如果我們在程式庫 (codebase) 進行雛形 (prototype) 設計時,每次都需要重新編譯和構建專案,才能在模擬器中看到結果。但在 SwiftUI 中,我們無需重新構建都可以隨時查看更改,十分方便。

我們有沒有辦法可以讓 UIKit 組件都變得如此方便?我們希望不需要花時間重新編譯和構建專案,就可以預覽或熱重載 (hot reload) UIKit 的更改。

實際上,我們是希望利用 SwiftUI 為 UIKit 視圖創建一個實時預覽系統。

實作的方法有很多,像是 @IBDesignable@IBInspectable 等簡單的標註 (annotation) 。

但如果你有用過這些標註,就會知道有時它會因為某些原因出現錯誤,有時可能不是最好的方法。

因此,在這篇文章中,我們會學習一個更簡單的新方法,來即時預覽我們的更改。如果你有用過 SwiftUI,可能已經知道這個方法,不過我們會添加一個小技巧,讓它可以用於 UIKit 中。

SwiftUI:PreviewProvider

PreviewProvider 是一個協定型別 (protocol type),在 Xcode 提供視圖預覽。當中包含一個名為 Preview 的關聯型別 (associated type),它是屬於 View 型別的。View是一個 SwiftUI 視圖,我們會 return 它,來讓 PreviewProvider 顯示預覽。我們稍後會再深入探討這一點。

創建好符合這個協定的物件後,我們就可以傳遞希望在預覽中看到的視圖。之後,螢幕就會像這樣自動彈出一個分割視圖 (split view):

如果無法加載預覽,不用擔心,只需要按以下的鍵盤快捷鍵,就可以重置實時預覽:

⌘ + ⌥ + Return (Command + option + Return)

備註:如果預覽視圖的右上角出現 Resume 按鈕,請點擊該按鈕。如果按鈕沒有出現,就代表預覽內容已經是最新的。

UIKit:PreviewProvider

現在大家都了解 PreviewProvider 及它在 SwiftUI 的操作原理,那我們如何在 UIKit 中實作呢?

答案很簡單:我們只需要把 UIKit 程式庫轉換為 SwiftUI 可以理解的內容,並使用 SwiftUI PreviewProvider 來查看內容的實時預覽就可以了!讓我們來看如何實作吧!

如何轉換 UIKit 內容為 SwiftUI 內容?

其實方法很簡單,不用想得太複雜。我們只需要使用 UIViewControllerRepresentable協定就可以了。

UIViewControllerRepresentable 就是把 UIViewController 轉換為 SwiftUI 視圖的橋樑。你猜到我們接下來要怎樣做了嗎?

實作

現在大家已經了解 SwiftUI 的 UIViewControllerRepresentablePreviewProvider,讓我們來一起動手實作吧!

UIKit Controller

首先,讓我們建立一個簡單的 UIKit Controller (UIViewController),當中包含一些 UI 設定:

class ViewController: UIViewController {

    @IBOutlet var imageView: UIImageView!
    @IBOutlet var titleLabel: UILabel!
    @IBOutlet var confirmBtn: UIButton!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        setupView()
    }
    
    private func setupView() {
        imageView.layer.cornerRadius = imageView.frame.height / 2
        imageView.clipsToBounds = true
        imageView.layer.borderWidth = 1
        imageView.layer.borderColor = UIColor.red.cgColor
        
        titleLabel.text = "This is a test ViewController to see if we can use swiftUI previews for UIKit Controllers"
        
        confirmBtn.setTitle("Confirm", for: .normal)
        confirmBtn.backgroundColor = .cyan
        confirmBtn.clipsToBounds = true
        confirmBtn.layer.borderWidth = 1
        confirmBtn.layer.borderColor = UIColor.blue.cgColor
        confirmBtn.layer.cornerRadius =  20
    }

}

如果我們執行這個 ViewController,會得到以下的結果:

接下來,我們要建立一個 SwiftUI Preview,讓我們可以實時看到 UIKit UI 的所有更改,不需要像之前那樣每次都重新編譯和構建專案。

把 UIViewController 轉換為 SwiftUI Controller

我們只需要在遵從 UIViewControllerRepresentable 的 Controller 中創建一個物件,讓它可以被 SwiftUI 讀取即可。

import Foundation

#if canImport(SwiftUI) && DEBUG
import SwiftUI

struct ViewControllerRepresentable: UIViewControllerRepresentable {
    
    func makeUIViewController(context: Context) -> some UIViewController {
        return UIStoryboard(name: "Main", bundle: nil).instantiateInitialViewController()!
    }
    
    func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {
        
    }
}
#endif

在上面的程式碼中:

  • canImport(SwiftUI) 是用來確保它只為支援 SwiftUI 的 iOS 版本進行編譯。
  • DEBUG 則確保它只在除錯環境中運行。

MakeUIViewController(context: Context) 函式中,我們只需要實例化想在預覽中看到的 Controller 即可。

在上面的程式碼中,我就實例化了 Main Storyboard。

利用 PreviewProvider 預覽 UIViewController

我們已經把 UIViewController 轉換為 SwiftUI Controller,只需要為 PreviewProvider 添加多幾行程式碼就完成了。

#endif 之前添加以下程式碼:

struct ViewController_Preview: PreviewProvider {    
    static var previews: some View {  
        ViewControllerRepresentable()        
    }
}

完整的程式碼應該是這樣的:

import Foundation

#if canImport(SwiftUI) && DEBUG
import SwiftUI

struct ViewControllerRepresentable: UIViewControllerRepresentable {
    
    func makeUIViewController(context: Context) -> some UIViewController {
        return UIStoryboard(name: "Main", bundle: nil).instantiateInitialViewController()!
    }
    
    func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {
        
    }
}

struct ViewController_Preview: PreviewProvider {
    static var previews: some View {
        ViewControllerRepresentable()
    }
}
#endif

現在,我們已經有了完整的程式庫,可以隨時查看 UIKit UIViewController 的實時預覽。你可以試試修改一下 UI,就會看到即時的改變。我們可以跟繁瑣的重構步驟說再見了!

這篇文章到此為止,謝謝你的閱讀。你可以在 GitHub 上參閱完整的程式碼。

本篇原文(標題:Build a SwiftUI PreviewProvider for UIKit Views)刊登於作者 Medium,由 Emad Beyrami 所著,並授權翻譯及轉載。
作者簡介:Emad Beyrami,iOS 開發者。
譯者簡介:Kelly Chan-AppCoda 編輯小姐。

作者
AppCoda 編輯團隊
此文章為客座或轉載文章,由作者授權刊登,AppCoda編輯團隊編輯。有關文章詳情,請參考文首或文末的簡介。
評論
更多來自 AppCoda 中文版
很好! 你已成功註冊。
歡迎回來! 你已成功登入。
你已成功訂閱 AppCoda 中文版 電子報。
你的連結已失效。
成功! 請檢查你的電子郵件以獲取用於登入的連結。
好! 你的付費資料已更新。
你的付費方式並未更新。