そろそろSwiftUI使ってもいいよね?
iOS14betaも発表されて、そろそろエンタープライズアプリもiOS13対応が許される季節になってきましたが、皆様いかがお過ごしでしょうか?
と言っても、実際には過去のプロジェクトはStoryboardで沢山の画面が作られているわけで、むしろ僕の触ってるプロジェクトはそもそもObjective-Cだったりするんですが、利用現場の端末のバージョンも上がってきて、そろそろiOS13 / watchOS6の機能を使えるような空気が漂ってきました。
iOSでStoryboardとSwiftUIを混ぜる方法は こちらの記事を参考にさせていただいて非常に助かりました。
ところが開発者の少ないwatchOS関連は探してもなかなか見つからないのです。そうですね。仕方ないからメモを残しておきます。
業務の終わりのタイミングで書いてるので本当にメモです。
storyboardなInterfaceControllerからSwiftUIに遷移
既存のInterfaceControllerからSwiftUIを呼ぶには、WKHostingController を使います。
https://developer.apple.com/documentation/swiftui/wkhostingcontroller
WKHostingController は InterfaceControllerを継承しているので、今までと同じ感覚でクラスを連携させれば呼べます。
まずは、今までのWKInterfaceControllerの代わりに WKHostingControllerでコントローラーclassを作ります。
import SwiftUI
class HomeViewInterfaceController : WKHostingController<HomeView> {
override var body: HomeView {
return HomeView()
}
}
import SwiftUI
struct Menu: Identifiable{
var id: Int
var name: String
init(id: Int, name: String){
self.id = id
self.name = name
}
}
class MenuList: ObservableObject{
@Published var list: [Menu]
init(){
self.list = [
Menu(id: 1, name:"Apple"),
Menu(id: 2, name:"Banana"),
Menu(id: 3, name:"Cookie"),
Menu(id: 4, name:"Donuts")]
}
}
struct HomeView: View {
@ObservedObject var mymenu: MenuList = MenuList()
var body: some View {
List {
ForEach(mymenu.list){ item in
NavigationLink(destination: SecondView(id: item.id)) {
Text("\(item.name)")
}
}
}
}
}
storyboardにinterfaceControllerを追加して、参照先のclassをHomeViewInterfaceController.swift に Identifierを "HomeViewInterfaceController"にします。
InterfaceControllerから SwiftUIを呼び出すには
[self pushControllerWithName:@"HomeViewInterfaceController" context:nil];
//rootViewとして呼び出すには
[WKInterfaceController reloadRootPageControllersWithNames:@[@"HomeViewInterfaceController"] contexts:nil orientation:WKPageOrientationVertical pageIndex:0];
といつものようにIdentifierを指定してあげればOK。
HomeからSwiftUIで定義されているSecondViewを呼び出すには、上の
NavigationLink(destination: SecondView(id: item.id)) {
Text("\(item.name)")
}
で呼び出せます。
SwiftUIからwatchKitのstoryboardのInterfaceControllerに遷移
public init(destinationName: String, @ViewBuilder label: () -> Label)
を使います。
NavigationLink(destinationName: "second") {
Text("\(item.name)")
}
SwiftUIからstoryboard のInterfaceControllerでrootViewsをリセット
Button(action: {
WKInterfaceController.reloadRootControllers(withNamesAndContexts: [(name: "second", context: [:] as AnyObject )])
}){
Text("second")
}