AppKit 上的 SwiftUI - 在弹出窗口中将焦点设置为 TextField
Posted
技术标签:
【中文标题】AppKit 上的 SwiftUI - 在弹出窗口中将焦点设置为 TextField【英文标题】:SwiftUI on AppKit - Set Focus to a TextField in a popover 【发布时间】:2021-04-18 19:56:06 【问题描述】:在下面的 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()
【问题讨论】:
【参考方案1】: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)
)
如果你想取消文本字段的焦点,你可以将它添加到 loadView 函数到 FocusedTextFieldViewController 并使用通知中心再次取消文本字段的焦点。
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)
但如果文本字段当前处于活动状态,这可能不起作用。
【讨论】:
如果我有一个带有几个 FocusedTextFields 的视图。焦点的顺序是如何定义的?如何以编程方式为另一个 FocusedTextField 提供焦点? FocusedTextFields 呈现为 5 行的“TextEditor”。我可以将其限制为一行吗(textField.maximumNumberOfLines = 1,仅防止字段中的换行符) 如果要聚焦另一个文本字段,需要调用NSViewController中的view.window?.makeFirstResponder(view)
方法。您可以像我一样使用通知让第一响应者辞职(这实际上不起作用),然后使视图成为第一响应者。我真的不知道“一行”是指文本字段的大小还是文本字段的行数。如果要限制行数,可以使用textField.usesSingleLineMode = true
。如果要设置大小,可以使用 SwiftUI 的帧修饰符:.frame(height: yourheight)
。 25 将是默认高度。以上是关于AppKit 上的 SwiftUI - 在弹出窗口中将焦点设置为 TextField的主要内容,如果未能解决你的问题,请参考以下文章
让我们在 MacOS AppKit 上的 SwiftUI 中使用所有可用宽度的按钮
如何在 AppKit 上的自定义 SwiftUI 表单中右对齐项目标签?