Skip to content

Instantly share code, notes, and snippets.

@defagos
Created September 28, 2021 21:04
Show Gist options
  • Save defagos/4effeed15031c1a59725e4f10b540ee9 to your computer and use it in GitHub Desktop.
Save defagos/4effeed15031c1a59725e4f10b540ee9 to your computer and use it in GitHub Desktop.
Send a message to the UIKit responder chain from a SwiftUI view
@objc protocol ExampleActions: AnyObject {
func pushUIKitViewController()
}
struct ExampleView: View {
@FirstResponder private var firstResponder
var body: some View {
Button {
firstResponder.sendAction(#selector(ExampleActions.pushUIKitViewController))
} label: {
Text("Push some UIKit view controller")
}
.responderChain(from: firstResponder)
}
}
import SwiftUI
extension View {
/**
* Provide access to the `UIKit` responder chain, rooted in a first responder inserted where the modifier
* is applied.
*/
func responderChain(from firstResponder: FirstResponder) -> some View {
return background(ResponderChain(firstResponder: firstResponder))
}
}
/**
* A view providing access to the `UIKit` responder chain.
*/
private struct ResponderChain: UIViewRepresentable {
let firstResponder: FirstResponder
func makeUIView(context: Context) -> UIView {
return UIView()
}
func updateUIView(_ uiView: UIView, context: Context) {
firstResponder.view = uiView
}
}
/**
* Provide access to a first responder. A property wrapper is used as syntactic sugar, and a class
* is required for mutation of the view property during SwiftUI body updates.
*/
@propertyWrapper class FirstResponder {
fileprivate weak var view: UIView?
var wrappedValue: FirstResponder {
return self
}
@discardableResult
func sendAction(_ action: Selector, for event: UIEvent? = nil) -> Bool {
return UIApplication.shared.sendAction(action, to: nil, from: view, for: event)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment