(Swift) 混合架構開發:將 SwiftUI 設為 Storyboard 的初始畫面
使用 SwiftUI 來建構畫面的速度非常快,相較於以往的 Storyboard,它省去了許多 AutoLayout 的設定以及元件的拖放。在大多數的情況下我們仍需要使用 Storyboard 來建構 APP 的畫面。但有些畫面也許使用 SwiftUI 來建構畫面會更為方便。這時就需要在原本的 StoryBoard 中新增一個 SwiftUI 來進行畫面建構,而這一篇最主要的問題就是『如何將SwiftUI 所建構的畫面設為 Storyboard 的初始畫面』。
目錄:
SwiftUI 基本的語法
UIHostingController
使用 Button 切換到 SwiftUI 畫面(IBAction 觸發)
使用 Button 切換到 SwiftUI 畫面(IBSegueAction 觸發)
將 SwiftUI 畫面設為開啟 APP 的的第一個畫面
在初始畫面是 SwiftUI 的情況下,跳轉到 Storyboard 中其它畫面
SwiftUI 基本的語法
UIHostingController
當需要將 SwiftUI 視圖整合到 UIKit 中,可以建立 UIHostingController 物件並指定根視圖。這樣就可以隨時變更 rootView 屬性,並像使用其他視圖控制器一樣使用它
使用 Button 切換到 SwiftUI 畫面(IBAction 觸發)
在 Storyboard 新增一個 SwiftUI View -> SwiftUIView
import SwiftUI
struct SwiftUIView: View {
var body: some View {
ZStack {
Color(red: 155/255, green: 190/255, blue: 200/255)
.ignoresSafeArea()
Text("This is SwiftUI View")
.font(.largeTitle)
.foregroundColor(.white)
}
}
}
#Preview {
SwiftUIView()
}
回到 Stroyboard 在 ViewController 新增一個 Button(SwiftUI) ,並拉 @IBAction func showSwiftUI
,記得要 import SwiftUI
@IBAction func showSwiftUI(_ sender: UIButton) {
let contentView = SwiftUIView()
let controller = UIHostingController(rootView: contentView)
present(controller, animated: true, completion: nil)
}
改成全頁顯示
controller.modalPresentationStyle = .fullScreen
使用 Button 切換到 SwiftUI 畫面(IBSegueAction 觸發)
在畫面新增 UIHostingController 也可以做到相同的效果
@IBSegueAction func showswiftUI(_ coder: NSCoder) -> UIViewController? {
return UIHostingController(coder: coder, rootView: SwiftUIView())
}
將 SwiftUI 畫面設為開啟 APP 的的第一個畫面
由於在 Storyboard 通常我們會在 Main 裡面選擇一個 Controller,並點選右側的 View Controller 中的 is initial View Controller,來當作畫面初始的 Controller,但是透過上面的兩種方建立 SwiftUI 顯然是不能開啟 APP 時,就跳轉到 SwiftUI 畫面,這時候就需要 Container View 來幫助我們
在 ViewController 新增一個 Container View ,並設定 AutoLayout,最後產生出的 ViewController 將其刪除
接下來在畫面新增 UIHostingController,並從 Container View 按下右鍵拖移到 UIHostingController ,選取 Embed
再來就是拉 @IBSegueAction
@IBSegueAction func showswiftUI(_ coder: NSCoder) -> UIViewController? {
return UIHostingController(coder: coder, rootView: SwiftUIView())
}
這樣一來初始的畫面就會是 SwiftUI 所建構的畫面
在初始畫面是 SwiftUI 的情況下,跳轉到 Storyboard 中其它畫面
例:一開始的登入畫面採用 SwiftUI 來建構,登入成功後跳轉到 Storyboard 中其它的 ViewController
就如剛開始前面提到的一樣,雖然使用 SwiftUI 建構畫面是相當快速的,但是採用 混合架構開發,當然也會遇到蠻多問題要解決的,你可以想像平常如何在 Storyboard 中切換畫面,最常使用的是按下 Button 後轉到下一個畫面,或是使用 present 或 show 來進行畫面轉換,但在使用 SwiftUI 的情況下,顯然這些方法在 SwiftUI 底下是行不通的,所以這時後就需要 Notification 來幫助我們
在 SwiftUIView
新增一個 Button
import SwiftUI
struct SwiftUIView: View {
var body: some View {
ZStack {
Color(red: 155/255, green: 190/255, blue: 200/255)
.ignoresSafeArea()
VStack(spacing: 20) {
Text("This is SwiftUI View")
.font(.largeTitle)
.foregroundColor(.white)
Button {
} label: {
Text("showSecondViewController")
}
}
}
}
}
#Preview {
SwiftUIView()
}
新增一個 Swift File Notification
import Foundation
struct AllNotification {
static let toSecondViewController = Notification.Name("toSecondViewController")
}
在 Storyboard 新增一個 SecondViewController
現在要做就是在 SwiftUIView
點選 Button showSecondViewController
後,跳轉到 SecondViewController
SwiftUIView
中的 Button 底下發布通知
Button {
// 發布通知
NotificationCenter.default.post(name: AllNotification.toSecondViewController, object: nil)
} label: {
Text("showSecondViewController")
}
SecondViewController
,並設定 Storyboard ID -> SecondViewController
ViewController
新增以下的 function toSecondViewController
@objc func toSecondViewController(noti: Notification) {
let sb = storyboard?.instantiateViewController(withIdentifier: "SecondViewController") as! SecondViewController
sb.modalPresentationStyle = .fullScreen
present(sb, animated: true, completion: nil)
}
最後在 viewDidLoad 新增 接收通知,大致上就完成了
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
// 接收通知
NotificationCenter.default.addObserver(self, selector: #selector(toSecondViewController(noti: )), name: AllNotification.toSecondViewController, object: nil)
}