Created
September 28, 2021 21:04
-
-
Save defagos/4effeed15031c1a59725e4f10b540ee9 to your computer and use it in GitHub Desktop.
Send a message to the UIKit responder chain from a SwiftUI view
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@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) | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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