Last active
October 1, 2024 06:13
-
-
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 { | |
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 { | |
.init() | |
} | |
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 { | |
self | |
} | |
@discardableResult | |
func sendAction(_ action: Selector, for event: UIEvent? = nil) -> Bool { | |
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