適当なUIViewControllerRepresentableビューコントローラーを作り追加して他のビューコントローラーへアクセスするコードです。多少強引で黒魔術っぽい方法だろうけど、どうしてもそうしたい時に。
import SwiftUI
public struct ControllerRepresenterView: UIViewControllerRepresentable {
public typealias UIViewControllerType = UIViewController
private final class ViewController: UIViewController {
var willAppear: (UIViewController) -> Void = { _ in }
var didAppear: (UIViewController) -> Void = { _ in }
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
willAppear(self)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
didAppear(self)
}
}
private let viewController = ViewController()
public init(
willAppear: @escaping (UIViewController) -> Void,
didAppear: @escaping (UIViewController) -> Void
) {
viewController.willAppear = willAppear
viewController.didAppear = didAppear
}
public func makeUIViewController(context: Context) -> UIViewControllerType {
viewController
}
public func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {
//
}
}
使用例
import SafariServices
struct ContentView: View {
func doNothing(uiViewController: UIViewController) {}
func example(uiViewController: UIViewController) {
// contentへアクセスする為に
guard let viewController = uiViewController.parent else { return }
// ex1: 黄色から青色へ
viewController.view.subviews.last?.backgroundColor = UIColor.systemBlue
// ex2: 1秒後にフルスクリーンモーダル表示
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
let a = "https://www.apple.com/"
guard let u = URL(string: a) else { return }
let c = SFSafariViewController(url: u)
c.modalPresentationStyle = .overFullScreen
viewController.present(c, animated: true, completion: nil)
}
}
var content: some View {
Color.yellow
}
var body: some View {
Group {
content
}
.background(
ControllerRepresenterView(willAppear: doNothing, didAppear: example)
)
}
}