AppKit 上的 SwiftUI - 将焦点设置到弹出窗口中的 TextField
SwiftUI on AppKit - Set Focus to a TextField in a popover
在下面的 AppKit 示例中,我希望第一个文本字段在弹出窗口出现时具有(键盘)焦点。
我怎样才能
- 将初始焦点设置到视图并
- 如何控制对焦顺序
- 如何以编程方式设置焦点,例如作为按钮操作
struct ContentView: View {
@State var showPopup = false
@State var text = ""
var body: some View {
VStack{
Text("Hello, world!")
.padding()
Button("show Popup") { showPopup = true}
}
.frame(width: 300, height: 300)
.padding()
.popover( isPresented: $showPopup,
arrowEdge: .trailing
) {
VStack{
Text("Popup")
TextField("enter Text",text:$text )
}
.padding()
}
}
}
I needed to do this in one of my projects myself。
首先,我将 NSViewController 子类化,其中视图在视图出现时成为第一响应者(聚焦)。
class FocusedTextFieldViewController: NSViewController, NSTextFieldDelegate {
@Binding var text: String
init(text: Binding<String>) {
_text = text
super.init(nibName: nil, bundle: nil)
}
required init?(coder: NSCoder) {
fatalError()
}
var textField: NSTextField!
override func loadView() {
// Set up the text field.
textField = NSTextField()
// Set the text field's delegate
textField.delegate = self
// Set an initial text value.
textField.stringValue = text
// Set the view to the new text field.
view = textField
}
override func viewDidAppear() {
// Make the view the first responder.
view.window?.makeFirstResponder(view)
}
func controlTextDidChange(_ obj: Notification) {
// Update the text.
text = textField.stringValue
}
}
然后,我使用 NSViewControllerRepresentable 在 SwiftUI 中显示 NSViewController。
struct FocusedTextField: NSViewControllerRepresentable {
@Binding var text: String
func makeNSViewController(context: Context) -> some FocusedTextFieldViewController {
return FocusedTextFieldViewController(text: $text)
}
func updateNSViewController(_ nsViewController: NSViewControllerType, context: Context) {
let textField = nsViewController.textField
textField?.stringValue = text
}
}
现在,您可以在 SwiftUI 中使用“FocusedTextField”了。
struct ContentView: View {
@State private var popoverIsPresented = false
@State private var text = ""
var body: some View {
Button("Show Popover") {
// Present the popover.
popoverIsPresented.toggle()
}
.popover(isPresented: $popoverIsPresented, content: {
FocusedTextField(text: $text)
})
}
}
如果您想取消文本字段的焦点,您可以将其添加到 FocusedTextFieldViewController 的 loadView 函数中,然后使用通知中心再次取消文本字段的焦点。
override func loadView() {
// Set up the text field.
textField = NSTextField()
// Set the text field's delegate
textField.delegate = self
// Set an initial text value.
textField.stringValue = text
// Set the view to the new text field.
view = textField
// Set up a notification for unfocusing the text field.
NotificationCenter.default.addObserver(forName: Notification.Name("UnfocusTextField"), object: nil, queue: nil, using: { _ in
// Unfocus the text field.
self.view.window?.resignFirstResponder()
})
}
然后你可以在任何时候想要取消文本字段的焦点时执行此操作。
NotificationCenter.default.post(name: Notification.Name("UnfocusTextField"), object: nil)
但如果文本字段当前处于活动状态,这可能不起作用。
在下面的 AppKit 示例中,我希望第一个文本字段在弹出窗口出现时具有(键盘)焦点。
我怎样才能
- 将初始焦点设置到视图并
- 如何控制对焦顺序
- 如何以编程方式设置焦点,例如作为按钮操作
struct ContentView: View {
@State var showPopup = false
@State var text = ""
var body: some View {
VStack{
Text("Hello, world!")
.padding()
Button("show Popup") { showPopup = true}
}
.frame(width: 300, height: 300)
.padding()
.popover( isPresented: $showPopup,
arrowEdge: .trailing
) {
VStack{
Text("Popup")
TextField("enter Text",text:$text )
}
.padding()
}
}
}
I needed to do this in one of my projects myself。 首先,我将 NSViewController 子类化,其中视图在视图出现时成为第一响应者(聚焦)。
class FocusedTextFieldViewController: NSViewController, NSTextFieldDelegate {
@Binding var text: String
init(text: Binding<String>) {
_text = text
super.init(nibName: nil, bundle: nil)
}
required init?(coder: NSCoder) {
fatalError()
}
var textField: NSTextField!
override func loadView() {
// Set up the text field.
textField = NSTextField()
// Set the text field's delegate
textField.delegate = self
// Set an initial text value.
textField.stringValue = text
// Set the view to the new text field.
view = textField
}
override func viewDidAppear() {
// Make the view the first responder.
view.window?.makeFirstResponder(view)
}
func controlTextDidChange(_ obj: Notification) {
// Update the text.
text = textField.stringValue
}
}
然后,我使用 NSViewControllerRepresentable 在 SwiftUI 中显示 NSViewController。
struct FocusedTextField: NSViewControllerRepresentable {
@Binding var text: String
func makeNSViewController(context: Context) -> some FocusedTextFieldViewController {
return FocusedTextFieldViewController(text: $text)
}
func updateNSViewController(_ nsViewController: NSViewControllerType, context: Context) {
let textField = nsViewController.textField
textField?.stringValue = text
}
}
现在,您可以在 SwiftUI 中使用“FocusedTextField”了。
struct ContentView: View {
@State private var popoverIsPresented = false
@State private var text = ""
var body: some View {
Button("Show Popover") {
// Present the popover.
popoverIsPresented.toggle()
}
.popover(isPresented: $popoverIsPresented, content: {
FocusedTextField(text: $text)
})
}
}
如果您想取消文本字段的焦点,您可以将其添加到 FocusedTextFieldViewController 的 loadView 函数中,然后使用通知中心再次取消文本字段的焦点。
override func loadView() {
// Set up the text field.
textField = NSTextField()
// Set the text field's delegate
textField.delegate = self
// Set an initial text value.
textField.stringValue = text
// Set the view to the new text field.
view = textField
// Set up a notification for unfocusing the text field.
NotificationCenter.default.addObserver(forName: Notification.Name("UnfocusTextField"), object: nil, queue: nil, using: { _ in
// Unfocus the text field.
self.view.window?.resignFirstResponder()
})
}
然后你可以在任何时候想要取消文本字段的焦点时执行此操作。
NotificationCenter.default.post(name: Notification.Name("UnfocusTextField"), object: nil)
但如果文本字段当前处于活动状态,这可能不起作用。