Skip to content

Instantly share code, notes, and snippets.

@ramzesenok
Last active October 18, 2022 17:10
Show Gist options
  • Save ramzesenok/d9d908c1e03b2aee4feaed80d3820821 to your computer and use it in GitHub Desktop.
Save ramzesenok/d9d908c1e03b2aee4feaed80d3820821 to your computer and use it in GitHub Desktop.
An approach to use SwiftUI views inside UIKit Coordinator
class Coordinator: UINavigationController {
init() {
super.init(nibName: nil, bundle: nil)
let firstVC = HostingController { FirstView(push: push) }
setViewControllers([firstVC], animated: false)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func push() {
let screen = SecondView(navigationPropagation: NavigationPropagation(), present: present)
let vc = HostingController(navigationPropagation: screen.navigationPropagation) { screen }
pushViewController(vc, animated: true)
}
func present() {
let vc = HostingController { ThirdView() }
present(vc, animated: true)
}
}
class HostingController<Content: View>: UIHostingController<Content> {
var subscriptions = Set<AnyCancellable>()
init(navigationPropagation: NavigationPropagation = NavigationPropagation(), @ViewBuilder _ view: () -> Content) {
super.init(rootView: view())
navigationPropagation.screenTitleSubject
.sink { [weak self] screenTitle in
self?.navigationItem.title = screenTitle
}
.store(in: &subscriptions)
navigationPropagation.leadingNavigationButtonsSubject
.sink { [weak self] leadingButtons in
self?.navigationItem.leftBarButtonItems = leadingButtons
}
.store(in: &subscriptions)
navigationPropagation.trailingNavigationButtonsSubject
.sink { [weak self] trailingButtons in
self?.navigationItem.rightBarButtonItems = trailingButtons
}
.store(in: &subscriptions)
}
@MainActor required dynamic init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
struct FirstView: View {
let push: () -> Void
var body: some View {
Button("Push", action: push)
}
}
struct SecondView: View {
let navigationPropagation: NavigationPropagation
let present: () -> Void
var body: some View {
VStack {
Button("Present", action: present)
Button("Change title") {
navigationPropagation.screenTitleSubject.send(String("qwertyuiopasdfghjklzxcvbnm".randomElement()!))
}
}
}
}
struct ThirdView: View {
var body: some View {
Text("Hello world!")
}
}
class NavigationPropagation {
let leadingNavigationButtonsSubject: CurrentValueSubject<[UIBarButtonItem], Never>
let trailingNavigationButtonsSubject: CurrentValueSubject<[UIBarButtonItem], Never>
let screenTitleSubject: CurrentValueSubject<String?, Never>
init(
screenTitle: String? = nil,
leadingNavigationButtons: [UIBarButtonItem] = [],
trailingNavigationButtons: [UIBarButtonItem] = []
) {
self.screenTitleSubject = CurrentValueSubject(screenTitle)
self.leadingNavigationButtonsSubject = CurrentValueSubject(leadingNavigationButtons)
self.trailingNavigationButtonsSubject = CurrentValueSubject(trailingNavigationButtons)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment