🧭
[SwiftUI] UIRepresentableViewController内のnavigationBar, barButtonの表示
問題
SwiftUIで構築しているViewから、UIViewController
のviewをUIRepresentableViewController
でラップして表示した。
そのUIViewController
には、viewDidLoad()
でnavigationItem
を設置したが、これが表示されない。
表示されないコード
HogeViewControllerを、UIRepresentableViewControllerでラップして、SwiftUIのviewから呼び出して表示させている状況を想定している。
class HogeViewController {
override func viewDidLoad() {
super.viewDidLoad()
let saveBarButtonItem = UIBarButtonItem(barButtonSystemItem: .save, target: self, action: #selector(saveBarButtonDidTouchUpInside))
navigationItem.rightBarButtonItems = [saveBarButtonItem]
}
...
}
期待される表示
画面上部の切り抜き。navigationBarにBarButtonItemが表示されている。
原因
1. UIViewControllerRepresentableでラップしたUIViewControllerのnavigationViewControllerは、呼び出し元のSwiftUI(self.parent)にある
SwiftUIは内部的には UINavigationController
を使っている。そのため、UIViewController
をSwiftUIのNavigationViewController
にUIViewControllerRepresentable
を使ってプッシュすると、当然そのNavigationController
はSwiftUIのものを使うことになり、UIViewController
のNavigationController
はnil
になる。
2. viewWillAppear()にならないとparentにアクセス出来ない
UIViewController
はviewDidLoad()
のタイミングでは、親のSwiftUIからはまだ見えない(ラップされてない)、つまりself.parent
がnil
になっているので、viewWillAppear()
でself.parent
にアクセスする。
解決法
class HogeViewController {
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
let saveBarButtonItem = UIBarButtonItem(barButtonSystemItem: .save, target: self, action: #selector(saveBarButtonDidTouchUpInside))
self.parent?.navigationItem.rightBarButtonItems = [saveBarButtonItem]
}
...
}
参考資料
Discussion