swiftswiftuiuikituiwindow

SwiftUI - Display view on UIWindow


I'm trying to display a custom SwiftUI view similar to a Toast in Android. My issue is that I would like to display this particular view above everything else, using the current UIWindow.

Currently, while working on static func displayToastAboveAll() located in my ToastView, this is how far i got

public struct ToastView: View {
    static func displayToastAboveAll() {
        let window = UIApplication.shared.windows.filter { $0.isKeyWindow }.first // window
        let viewToShow = ToastView(my params) // my view to display

        // This part I'm not sure of
        let hostingController = UIHostingController(rootView: viewToShow)
        window?.addSubview(hostingController.view)
    }

    public var body: some View {
        // MyDesign
    }
}

Any idea how should I use the window to put the ToastView at its proper place, and still being able to navigate within the app (and use the outlets) while having the view displayed ?


Solution

  • I managed to do what I wanted. Basically, this code is working, but I had to remove some constraints from my SwiftUI view and add them with UIKit using the static func. Also, I had to pass by a modifier (see below) and put ToastView init in private.

    public struct ToastModifier: ViewModifier {
        public func body(content: Content) -> some View {
            content
        }
    }
    
    extension View {
        public func toast() -> some View {
            ToastView.displayToastAboveAll()
            return modifier(ToastModifier())
        }
    }
    
    

    This is done to force the use of either modifier (SwiftUI, by doing .toast, just like you'd do .alert) or directly by calling the static func ToastView.displayToastAboveAll() (UIKit). Indeed, I dont wont this Toast to be a part of the view, I want to trigger it like an alert.

    Finally, special warning because passing ToastView into UIHostingViewController will mess with some of the animations. I had to rewrite animations in UIKit in order to have a nice swipe & fade animation.