SwiftUI iOS - 如何捕捉硬件按键事件
SwiftUI iOS - how to capture hardware key events
我是 iOS 开发的新手。按照教程,我使用 SwiftUI 创建了一个简单的计算器。
我的 iPad 上连接了一个键盘,我希望能够使用键盘输入值。
如何在 SwiftUI 应用程序(没有文本字段)中捕获和处理硬件键盘事件?
我已尝试在 SceneDelegate (UIResponder) 上使用 keyCommand,如此处所示,但这对我不起作用。只要我在 iPad 上按任意键,我就会在 XCode 跟踪视图中看到“与守护进程的连接无效”。
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
override var canBecomeFirstResponder: Bool {
return true;
}
override var keyCommands: [UIKeyCommand]? {
return [
UIKeyCommand(input: "a", modifierFlags: [], action: #selector(test)),
UIKeyCommand(input: UIKeyCommand.inputLeftArrow, modifierFlags: [], action: #selector(test))
]
}
@objc func test(_ sender: UIKeyCommand) {
print("test was pressed")
}
谢谢
它需要改写托管视图控制器,一切正常。使用 Xcode 11.2 / iOS 13.2
测试
这是示例代码
class KeyTestController<Content>: UIHostingController<Content> where Content: View {
override func becomeFirstResponder() -> Bool {
true
}
override var keyCommands: [UIKeyCommand]? {
return [
UIKeyCommand(input: "1", modifierFlags: [], action: #selector(test)),
UIKeyCommand(input: "0", modifierFlags: [], action: #selector(test)),
UIKeyCommand(input: UIKeyCommand.inputLeftArrow, modifierFlags: [], action: #selector(test))
]
}
@objc func test(_ sender: UIKeyCommand) {
print(">>> test was pressed")
}
}
以及下方 SceneDelegate
的某处
window.rootViewController = KeyTestController(rootView: contentView)
如果您使用的是 SwiftUI 生命周期,@Asperi 还展示了如何在此 post - Hosting Controller When Using iOS 14 @main.
中访问 rootViewController
总而言之,HostingWindowFinder
追踪 rootViewController
的可变版本并提供对它的访问。
struct ContentView: View {
var body: some View {
Text("Demo Root Controller access")
.withHostingWindow { window in
window?.rootViewController = KeyController(rootView: ContentView())
}
}
}
extension View {
func withHostingWindow(_ callback: @escaping (UIWindow?) -> Void) -> some View {
self.background(HostingWindowFinder(callback: callback))
}
}
struct HostingWindowFinder: UIViewRepresentable {
var callback: (UIWindow?) -> ()
func makeUIView(context: Context) -> UIView {
let view = UIView()
DispatchQueue.main.async { [weak view] in
self.callback(view?.window)
}
return view
}
func updateUIView(_ uiView: UIView, context: Context) {
}
}
还有
如果您只想监视原始键盘输入,请使用 pressesBegan(...)
- WWDC 2019 Talk
class KeyController<Content>: UIHostingController<Content> where Content: View {
override func pressesBegan(_ presses: Set<UIPress>, with event: UIPressesEvent?) {
for press in presses {
guard let key = press.key else { continue }
print(key)
}
}
}
非常感谢@Asperi! ❤️
我是 iOS 开发的新手。按照教程,我使用 SwiftUI 创建了一个简单的计算器。
我的 iPad 上连接了一个键盘,我希望能够使用键盘输入值。
如何在 SwiftUI 应用程序(没有文本字段)中捕获和处理硬件键盘事件? 我已尝试在 SceneDelegate (UIResponder) 上使用 keyCommand,如此处所示,但这对我不起作用。只要我在 iPad 上按任意键,我就会在 XCode 跟踪视图中看到“与守护进程的连接无效”。
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
override var canBecomeFirstResponder: Bool {
return true;
}
override var keyCommands: [UIKeyCommand]? {
return [
UIKeyCommand(input: "a", modifierFlags: [], action: #selector(test)),
UIKeyCommand(input: UIKeyCommand.inputLeftArrow, modifierFlags: [], action: #selector(test))
]
}
@objc func test(_ sender: UIKeyCommand) {
print("test was pressed")
}
谢谢
它需要改写托管视图控制器,一切正常。使用 Xcode 11.2 / iOS 13.2
测试这是示例代码
class KeyTestController<Content>: UIHostingController<Content> where Content: View {
override func becomeFirstResponder() -> Bool {
true
}
override var keyCommands: [UIKeyCommand]? {
return [
UIKeyCommand(input: "1", modifierFlags: [], action: #selector(test)),
UIKeyCommand(input: "0", modifierFlags: [], action: #selector(test)),
UIKeyCommand(input: UIKeyCommand.inputLeftArrow, modifierFlags: [], action: #selector(test))
]
}
@objc func test(_ sender: UIKeyCommand) {
print(">>> test was pressed")
}
}
以及下方 SceneDelegate
的某处
window.rootViewController = KeyTestController(rootView: contentView)
如果您使用的是 SwiftUI 生命周期,@Asperi 还展示了如何在此 post - Hosting Controller When Using iOS 14 @main.
中访问rootViewController
总而言之,HostingWindowFinder
追踪 rootViewController
的可变版本并提供对它的访问。
struct ContentView: View {
var body: some View {
Text("Demo Root Controller access")
.withHostingWindow { window in
window?.rootViewController = KeyController(rootView: ContentView())
}
}
}
extension View {
func withHostingWindow(_ callback: @escaping (UIWindow?) -> Void) -> some View {
self.background(HostingWindowFinder(callback: callback))
}
}
struct HostingWindowFinder: UIViewRepresentable {
var callback: (UIWindow?) -> ()
func makeUIView(context: Context) -> UIView {
let view = UIView()
DispatchQueue.main.async { [weak view] in
self.callback(view?.window)
}
return view
}
func updateUIView(_ uiView: UIView, context: Context) {
}
}
还有
如果您只想监视原始键盘输入,请使用 pressesBegan(...)
- WWDC 2019 Talk
class KeyController<Content>: UIHostingController<Content> where Content: View {
override func pressesBegan(_ presses: Set<UIPress>, with event: UIPressesEvent?) {
for press in presses {
guard let key = press.key else { continue }
print(key)
}
}
}