Skip to content

Instantly share code, notes, and snippets.

@GeekAndDad
Last active November 17, 2019 05:08
Show Gist options
  • Save GeekAndDad/757d4a30c41f2a567c46244c0bd31763 to your computer and use it in GitHub Desktop.
Save GeekAndDad/757d4a30c41f2a567c46244c0bd31763 to your computer and use it in GitHub Desktop.
Using UIViewController via the SwiftUI Environment
//
// ContentView.swift
// TestSwiftUI1
//
//
import SwiftUI
struct ContentView: View {
@Environment(\.viewController) private var viewControllerHolder: UIViewController?
private var viewController: UIViewController? {
self.viewControllerHolder
}
var body: some View {
Button("Show Modal") {
self.viewController?.present(style: .fullScreen) {
ModalView(title: "Sweet!", subtitle: "full screen?")
}
}
}
}
struct ModalView: View {
@Environment(\.viewController) private var viewControllerHolder: UIViewController?
let title: String
let subtitle: String
var body: some View {
VStack(spacing: 20) {
Text(title).font(.largeTitle)
Text(subtitle).font(.title).foregroundColor(.gray)
Text("By changing the State var you can trigger the sheet to show")
.frame(maxWidth: .infinity)
.padding().font(.title).layoutPriority(1)
.background(Color.red).foregroundColor(.white)
Spacer()
Button("Dismiss") {
self.viewControllerHolder?.dismiss(animated: true, completion: nil)
}
.accentColor(.red)
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
//
// UIViewController+SwiftUI.swift
//
// Created by Timothy Costa on 2019/07/04.
// Modified (fixed) by Dad 2019.11.16
// Copyright © 2019 timothycosta.com. All rights reserved.
// from his gist here: https://gist.github.com/timothycosta/a43dfe25f1d8a37c71341a1ebaf82213
// which he referenced in a StackOverflow post here: https://stackoverflow.com/a/56880640/145108
//
import SwiftUI
struct ViewControllerHolder {
weak var value: UIViewController?
}
struct ViewControllerKey: EnvironmentKey {
static var defaultValue: ViewControllerHolder { return ViewControllerHolder(value: UIApplication.shared.windows.first?.rootViewController ) }
}
extension EnvironmentValues {
var viewController: UIViewController? {
get { return self[ViewControllerKey.self].value }
set { self[ViewControllerKey.self].value = newValue }
}
}
extension UIViewController {
func present<Content: View>(style: UIModalPresentationStyle = .automatic, @ViewBuilder builder: () -> Content) {
let toPresent = UIHostingController(rootView: AnyView(EmptyView()))
toPresent.modalPresentationStyle = style
toPresent.rootView = AnyView(
builder()
.environment(\.viewController, toPresent)
)
self.present(toPresent, animated: true, completion: nil)
}
}
@GeekAndDad
Copy link
Author

Note this comment on the SO post:

To dismiss the ViewController I pass it to my View and then call self.vc?.dismiss(animated: true, completion: {}) but I have the suspicion that this still keeps something in memory because when I call this again and then trigger an update on a Publisher and catch it via onReceive() it gets called as often as I've opened and dismissed the ViewController any thoughts? – krjw Oct 17 at 17:01

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment