I’m working on a mixed project (SwiftUI + UIKit), so I have to use the UINavigationController as the root controller of my window. (or I cannot push any UIKitViewController)
The root is like this:
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
guard let windowScene = scene as? UIWindowScene else {
return
}
let window = UIWindow(windowScene: windowScene)
window.makeKeyAndVisible()
window.overrideUserInterfaceStyle = .light
self.window = window
//UIKit Navigation as root
let rootHubView = AnyView(SwiftUIView1())
let rootHubVC = UIHostingController(rootView: rootHubView)
let rootNavC = UINavigationController(rootViewController: rootHubVC)
window.rootViewController = rootNavC
}
Inside the SwiftUIView1, it has a StateObject
class TestingState: ObservableObject, Equatable {
static func == (lhs: TestingState, rhs: TestingState) -> Bool {
lhs.currentJourneyLevel == lhs.currentJourneyLevel
}
@Published var currentJourneyLevel: Int {
willSet {
debugPrint("##### currentJourneyLevel will be set from (currentJourneyLevel) to (newValue)")
}
}
init() {
currentJourneyLevel = 1
}
}
struct SwiftUIView1: View {
@StateObject private var testingState = TestingState()
@State var isActived = false {
didSet {
debugPrint("##### isActived: (isActived)")
}
}
var body: some View {
VStack (spacing: 30) {
Button("NextPage") {
testingState.currentJourneyLevel = 2
}
NavigationLink(
destination: SwiftUIView1(state: testingState),
isActive: $isActived
) { EmptyView() }
}
.onChange(of: testingState.currentJourneyLevel) { currentJourneyLevel in
debugPrint("##### currentJourneyLevel is onChange to: (currentJourneyLevel)")
isActived = currentJourneyLevel == 2
}
.navigationTitle("SwiftUIView1")
.navigationBarTitleDisplayMode(.inline)
}
}
And inside SwiftUIView2, it has another button to set the currentJourneyLevel back to 1 to pop it to the first view, like this:
struct SwiftUIView2: View {
private var state: TestingState
init(state: TestingState) {
self.state = state
}
var body: some View {
ZStack {
VStack(spacing: 10) {
Button("Back") {
state.currentJourneyLevel = 1
}
}
.navigationTitle("SwiftUIView2")
}
}
}
Once I click the NextPage button, is working as expected, currentJourneyLevel changed to 2 and then the onChange block be called, finally the isActived will be set to true, this is the log:
"##### currentJourneyLevel will be set from 1 to 2"
"##### currentJourneyLevel is onChange to: 2"
"##### isActived: true"
The problem is:
When I’m trying to get back from the second view, the onChange block is not called by the system as expected.
From the log I can see the the value of currentJourneyLevel has been changed correctly, but seems like the system observer is not working, it doesn’t call the onChange method as it should be.
"##### currentJourneyLevel will be set from 2 to 1"
However, if I changed to navigation to pure SwiftUI one like this:
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
guard let windowScene = scene as? UIWindowScene else {
return
}
let window = UIWindow(windowScene: windowScene)
window.makeKeyAndVisible()
window.overrideUserInterfaceStyle = .light
self.window = window
//Pure SwiftUI Navigation
let rootHubView = NSContainerView()
let rootHubVC = UIHostingController(rootView: rootHubView)
window.rootViewController = rootHubVC
//UIKit Navigation as root
// let rootHubView = AnyView(RootHubPlugin().getHubPage())
// let rootHubVC = UIHostingController(rootView: rootHubView)
// let rootNavC = UINavigationController(rootViewController: rootHubVC)
// window.rootViewController = rootNavC
}
struct NSContainerView: View {
var body: some View {
NavigationView {
AnyView(RootHubPlugin().getHubPage())
}
}
}
Everything will be working smoothly like this:
Click NextPage button:
"##### currentJourneyLevel will be set from 1 to 2"
"##### currentJourneyLevel is onChange to: 2"
"##### isActived: true"
Click Back button:
"##### currentJourneyLevel will be set from 2 to 1"
"##### currentJourneyLevel is onChange to: 1"
"##### isActived: false"
So,
what should I do to make the onChange block working with UIKitNavigationController?
Or if I just made any mistake?
Any suggestions will be greatly appreciated