I am trying to build a SwiftUI app in which a user can tab through several textfields laid out in a grid. The default behavior with the SwiftUI TextField does not work for me (I want the focus to proceed from top-to-bottom, rather than left-to-right) so I am trying to make a custom textfield by making NSTextField conform to NSViewRepresentable.
The code below displays in my application just fine, and the coordinator is initialized properly (it prints to the console), but none of the coordinator methods are ever called (they don't print anything). Am I doing something wrong? How do I fix this?
import SwiftUI
struct OrderedTextField: NSViewRepresentable {
@Binding var text: String
@Binding var selectedField: Int
var tag: Int
func makeNSView(context: NSViewRepresentableContext<OrderedTextField>) -> NSTextField {
let textField = NSTextField()
textField.delegate = context.coordinator
textField.tag = tag
textField.placeholderString = ""
return textField
}
func makeCoordinator() -> Coordinator {
Coordinator(text: $text)
}
func updateNSView(_ nsView: NSTextField, context: NSViewRepresentableContext<OrderedTextField>) {
nsView.delegate = context.coordinator
context.coordinator.newSelection = { newSelection in
DispatchQueue.main.async {
self.selectedField = newSelection
}
}
if nsView.tag == self.selectedField {
nsView.becomeFirstResponder()
}
}
}
extension OrderedTextField {
class Coordinator: NSObject, NSTextFieldDelegate {
@Binding var text: String
var newSelection: (Int) -> () = { _ in }
init(text: Binding<String>) {
print("Initializing!")
_text = text
}
func textShouldBeginEditing(_ textObject: NSText) -> Bool {
print("Should begin editing!")
return true
}
func textDidBeginEditing(_ notification: Notification) {
print("Began editing")
}
func textDidChange(_ notification: Notification) {
print("textDidChange")
}
func textShouldEndEditing(_ textObject: NSText) -> Bool {
print("should end editing")
return true
}
func textDidEndEditing(_ notification: Notification) {
print("did end editing")
}
}
}
Selecting any option will automatically load the page