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 中文版
如何使用 Swift 整合 Google Gemini AI
SwiftUI 框架

如何使用 Swift 整合 Google Gemini AI

在即將到來的 WWDC,Apple 預計將會發佈一個本地端的大型語言模型 (LLM)。 接下來的 iOS SDK 版本將讓開發者更輕易地整合 AI 功能至他們的應用程式中。然而,當我們正在等待 Apple 推出自家的生成 AI 模型時,其他公司(如 OpenAI
很好! 你已成功註冊。
歡迎回來! 你已成功登入。
你已成功訂閱 AppCoda 中文版 電子報。
你的連結已失效。
成功! 請檢查你的電子郵件以獲取用於登入的連結。
好! 你的付費資料已更新。
你的付費方式並未更新。