简体   繁体   中英

SwiftUI - Presenting alerts, dialogs from Views

I created an application in SwiftUI.

Views are structs, but I need to know the View Controller because it is needed for presenting some special alerts.

I see that in my project there are AppDelegate, and SceneDelegate.

I found this

let contentView = ContentView()

    // Use a UIHostingController as window root view controller.
    if let windowScene = scene as? UIWindowScene {
        let window = UIWindow(windowScene: windowScene)
        window.rootViewController = UIHostingController(rootView: contentView)
        self.window = window
        window.makeKeyAndVisible()
    }

So I want to pass the View Controller reference to the other Views.

Is window.rootViewController the right value to pass and use?

The possible solution is to inject hosting view controller as environment key, so it can be available at any ContentView internal hierarchy level.

Here is a demo. Tested with Xcode 12 / iOS 14.

  1. Declare environment key
struct RootViewControllerKey: EnvironmentKey {
    static let defaultValue: UIViewController? = nil
}

extension EnvironmentValues {
    var rootViewController: UIViewController? {
        get { self[RootViewControllerKey.self] }
        set { self[RootViewControllerKey.self] = newValue }
    }
}
  1. Inject environment into ContentView
if let windowScene = scene as? UIWindowScene {
    let window = UIWindow(windowScene: windowScene)

    let rootController = UIHostingController(rootView: AnyView(EmptyView()))
    rootController.rootView = AnyView(contentView
        .environment(\.rootViewController, rootController))
    window.rootViewController = rootController

    self.window = window
    window.makeKeyAndVisible()
}
  1. Use inside
struct ContentView: View {
    // can be used here as well

    var body: some View {
      TestSubView()
    }
}

struct TestSubView: View {
    @Environment(\.rootViewController) var viewController // for demo here!!

    var body: some View {
      Text("Demo")
        .onAppear {
          print(String(describing: self.viewController))
        }
    }
}

I do not know if this answer is a suitable solution, but it simply works for me, so be careful when using it.

class func getTopMostViewController() -> UIViewController? {
    var topMostViewController = UIApplication.shared.keyWindow?.rootViewController

    while let presentedViewController = topMostViewController?.presentedViewController {
        topMostViewController = presentedViewController
    }

    return topMostViewController
}

the use the value like

let viewController=getTopMostViewController()
viewController.present(...

from StackOverflow answer:

Get top most UIViewController

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM