🧭
[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