watchOS Xcode项目中如何同时使用Storyboard与SwiftUI
watchOS 下 Storyboard 与 SwiftUI 混编实现方法
你观察的没错,watchOS 没有UIKit体系的UIViewController和UIHostingController,但WatchKit框架提供了对等的桥接类WKHostingController,专门承担SwiftUI视图和WatchKit界面栈的桥接工作,整体实现逻辑和iOS端的混编思路一致,只需要替换为WatchKit对应的类即可,具体流程如下:
- 先正常编写你需要嵌入的SwiftUI视图,写法和普通SwiftUI页面没有区别,不需要做特殊适配,示例:
import SwiftUI struct MySwiftUIContent: View { // 可以正常定义需要传的参数 var displayText: String var tapAction: () -> Void var body: some View { VStack(spacing: 12) { Text(displayText) .font(.headline) Button("操作按钮") { tapAction() } } } }
- 如果你要通过Storyboard的segue直接跳转到SwiftUI页面:
打开Watch端的Storyboard文件,从组件库搜索找到watchOS分类下的Hosting Controller,拖入Storyboard画布。创建一个继承自WKHostingController的子类,在子类中指定要承载的SwiftUI根视图:
回到Storyboard,选中刚拖入的Hosting Controller,在身份检查器面板把它的自定义类设置为你刚写的import WatchKit import SwiftUI class MySwiftUIHostController: WKHostingController<MySwiftUIContent> { // 按需给SwiftUI视图传参、绑定回调 override var body: MySwiftUIContent { MySwiftUIContent(displayText: "来自Storyboard跳转的SwiftUI页面") { print("SwiftUI内按钮点击") } } }MySwiftUIHostController,之后就可以和普通WKInterfaceController一样,给它设置Storyboard ID、从其他界面控件拉segue连线,跳转逻辑和你之前纯Storyboard开发的操作完全一致。- 如果你要通过Storyboard的segue直接跳转到SwiftUI页面:
- 如果你要从现有Storyboard绑定的
WKInterfaceController中用代码弹出SwiftUI页面,不需要在Storyboard里拖入Hosting Controller节点,直接在代码里初始化桥接控制器弹出即可:
import WatchKit import SwiftUI // 这是你原有Storyboard关联的界面控制器 class OriginalStoryboardController: WKInterfaceController { // 比如原有界面上的按钮点击事件 @IBAction func popupSwiftUIAction() { let swiftUIView = MySwiftUIContent(displayText: "代码弹出的SwiftUI页面") { [weak self] in // 回调里可以正常调用原有WatchKit界面的逻辑 self?.dismiss() } let hostController = WKHostingController(rootView: swiftUIView) presentController(hostController) } }- 如果你要从现有Storyboard绑定的
- 注意要点:
- 所有涉及桥接的代码必须同时导入
WatchKit和SwiftUI两个框架,不要误导入UIKit相关类 - 该方案支持watchOS 6及以上系统,也就是SwiftUI最低兼容的watchOS版本,不需要额外引入第三方依赖
- SwiftUI页面和原有Storyboard页面的交互传值,既可以在初始化
WKHostingController时直接给SwiftUI视图传参,也可以通过ObservableObject、闭包等方式实现双向绑定,逻辑和iOS端UIKit与SwiftUI混编的传值方式一致 - SwiftUI页面弹出后,调用系统的
dismiss()方法即可回到原有Storyboard的界面栈,不需要做额外的导航栈处理
- 所有涉及桥接的代码必须同时导入
内容的提问来源于stack exchange,提问作者cagnulein
相关产品推荐
相关产品推荐

