Reputation: 6487
I have the following flow in a sample SwiftUI example which is very handy. It basically checks for a flag in UserDefaults
whether an intro view has been shown before or not, and based on it loads the ContentView
or IntroView
. Once IntroView
has been shown and the user taps the IntroView
, it automatically switches back to ContentView
. This is really a good feature in SwiftUI where the App
struct observes the bool and recomputes WindowGroup
.
Problem: I have an existing UIKit based app based on Storyboard and I am slowly injecting SwiftUI views into it using UIHostingController
. But I don't really get SwiftUI app lifecycle benefits like above in it and it becomes cumbersome. For instance, after showing IntroView
, I might need to show another view such as PermissionsView
where I ask for camera and photo library permissions which the user can alter anytime in iOS Settings. In SwiftUI, the code such as below automatically watches any changes and pops the IntroView
or PermissionsView
. How do I do this in my UIKit
based app? Is it possible to migrate the UIApplicationDelegate
& SceneDelegate
code to SwiftUI App
while still having view controllers load from Storyboard?
@main
struct TestSwiftUIIntroViewsApp: App {
@AppStorage("showedIntroView") var showedIntroView: Bool = false
var body: some Scene {
WindowGroup {
if showedIntroView {
ContentView()
} else {
IntroView()
}
}
}
}
struct ContentView: View {
var body: some View {
VStack {
Text("Content View")
}
.padding()
}
}
struct IntroView: View {
@AppStorage("showedIntroView") var showedIntroView: Bool = false
var body: some View {
VStack(alignment: .center, content: {
Text("Intro View")
})
.onTapGesture {
showedIntroView = true
}
}
}
Upvotes: 0
Views: 185
Reputation: 2093
I don't know if I'm getting this right, but yes, you can load storyboard views or any UIViewController view doing something like this:
struct MyView: UIViewControllerRepresentable {
func makeUIViewController(context: Context) -> MyViewController {
// For Storyboard views
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let viewController = storyboard.instantiateViewController(withIdentifier: "MyViewController") as! MyViewController
// For manually created UIViewControllers
/*
let vc = MyAwesomeViewController()
return vc
*/
return viewController
}
func updateUIViewController(_ uiViewController: MyViewController, context: Context) {
// Update the view controller here
}
}
Then you can use the above code like it was a SwiftUI view:
struct ContentView: View {
var body: some View {
MyView()
}
}
Also, I don't know how old is your app but it seems pretty recent to me, but it was common practice to use AppDelegate (and even before SceneDelegate) in SwiftUI apps. If you want to use an AppDelegate or your existing one into your SwiftUI app you can by declaring it into the struct that conforms to App in your SwiftUI project like this:
@UIApplicationDelegateAdaptor(MyAppDelegate.self) var appDelegate
And it should work like it was in a UIKit this way. I hope I was able to at least help you partially. Have a nice coding day!
Upvotes: 1