macOS SwiftUI中Sheet内TextField无法获取焦点问题求助
macOS SwiftUI Sheet内TextField无法获取焦点问题及解决方法
问题描述
在macOS应用的SwiftUI Sheet中放置TextField后,Sheet弹出时TextField无法获取任何焦点,焦点状态似乎被系统机制覆盖。但将TextField放在Sheet外时可正常工作,怀疑这是Sheet、Alert等弹出组件的通用Bug。
问题验证代码
无法正常工作的代码
import SwiftUI import PlaygroundSupport struct ContentView: View { @State private var text = "" @FocusState private var focus: Bool @State private var showSheet = false var body: some View { Button(action : { showSheet = true }) { Label("Add", systemImage: "plus") } .frame(width: 150, height: 50) .sheet(isPresented: $showSheet) { LabeledContent { TextField("Enter Text", text: $text, onCommit: { focus = false }) .focused($focus) // 此设置无效 } label: { Text("Field") } .padding() .defaultFocus($focus, false) // 此设置也无效 } } } PlaygroundPage.current.setLiveView(ContentView())
可正常工作的代码
import SwiftUI import PlaygroundSupport struct ContentView: View { @State private var text = "" @FocusState private var focus: Bool var body: some View { LabeledContent { TextField("Enter Text", text: $text, onCommit: { focus = false }) .focused($focus) } label: { Text("Field") } .padding() .defaultFocus($focus, false) } } PlaygroundPage.current.setLiveView(ContentView())
测试环境:Xcode 15.0.1,macOS 14.1.1
临时解决方法
方法一:延迟触发焦点设置
利用onAppear结合短暂延迟,手动将焦点赋予TextField:
.sheet(isPresented: $showSheet) { LabeledContent { TextField("Enter Text", text: $text, onCommit: { focus = false }) .focused($focus) } label: { Text("Field") } .padding() .onAppear { // 延迟0.1秒确保Sheet完成渲染后设置焦点 DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { focus = true } } }
方法二:通过AppKit底层API设置第一响应者
自定义基于NSViewRepresentable的TextField,直接调用AppKit的makeFirstResponder方法强制获取焦点:
struct FocusableTextField: NSViewRepresentable { @Binding var text: String @Binding var isFocused: Bool func makeNSView(context: Context) -> NSTextField { let textField = NSTextField() textField.delegate = context.coordinator textField.placeholderString = "Enter Text" return textField } func updateNSView(_ nsView: NSTextField, context: Context) { nsView.stringValue = text if isFocused && nsView.window?.firstResponder != nsView { nsView.window?.makeFirstResponder(nsView) } } func makeCoordinator() -> Coordinator { Coordinator(self) } class Coordinator: NSObject, NSTextFieldDelegate { var parent: FocusableTextField init(_ parent: FocusableTextField) { self.parent = parent } func controlTextDidChange(_ obj: Notification) { guard let textField = obj.object as? NSTextField else { return } parent.text = textField.stringValue } func controlTextDidEndEditing(_ obj: Notification) { parent.isFocused = false } } } // 在ContentView中使用自定义TextField .sheet(isPresented: $showSheet) { LabeledContent { FocusableTextField(text: $text, isFocused: $focus) } label: { Text("Field") } .padding() .onAppear { focus = true } }
Bug说明
这是SwiftUI在macOS平台上针对弹出组件(Sheet、Alert)的已知焦点管理问题,在Xcode 15及macOS 14版本中存在,目前官方尚未修复,上述方法可作为临时解决方案绕过该问题。
内容的提问来源于stack exchange,提问作者Denny L.
相关产品推荐
相关产品推荐

