我有一个 SwiftUI List
(在 macOS 上),我想在每一行显示一些内容TextFields
,并观察焦点在选择或取消选择单个文本字段时如何变化。如果我只在每一行List
显示一个纯文本TextField
,这似乎可以正常工作,但如果我将其嵌入视图TextField
内部Button
,焦点更改通知将停止工作。我想要“按钮”功能,以便用户可以点击行上的任意位置并激活文本字段,而不是精确点击文本字段边界。
以下是一些代码来演示问题。List
如果您RowView
取消注释 (1),则焦点更改通知会起作用。如果您注释掉 (1) 并取消注释RowViewWithButton
(2),则按钮功能会起作用,但我无法再收到焦点更改通知。
import SwiftUI
// test on macOS target
struct ContentView: View {
@State private var textFields = Array(repeating: "", count: 4)
@FocusState private var focusedField: Int?
var body: some View {
List(0..<4, id: \.self) { index in
// 1. works with focus notification changes
RowView(index: index, text: $textFields[index], focusedField: $focusedField)
// 2. button works, but no focus notifications on text field
//RowViewWithButton(index: index, text: $textFields[index], focusedField: $focusedField)
}
}
}
struct RowView: View {
let index: Int
@Binding var text: String
@FocusState.Binding var focusedField: Int?
var body: some View {
HStack {
Text("Row \(index + 1):")
TextField("", text: $text)
.multilineTextAlignment(.leading)
.focused($focusedField, equals: index)
}
.onChange(of: focusedField) { newFocus in
if newFocus == index {
print("TextField \(index) is in focus")
} else {
print("TextField \(index) lost focus")
}
}
.padding(.vertical, 4)
}
}
struct RowViewWithButton: View {
let index: Int
@Binding var text: String
@FocusState.Binding var focusedField: Int?
var body: some View {
Button (action: {
print("RowView - button selected at index \(index)")
focusedField = index
}) {
HStack {
Text("Row \(index + 1):")
TextField("", text: $text)
.multilineTextAlignment(.leading)
.focused($focusedField, equals: index)
}
.onChange(of: focusedField) { newFocus in
if newFocus == index {
print("TextField \(index) is in focus")
} else {
print("TextField \(index) lost focus")
}
}
.foregroundColor(.primary)
}
.buttonStyle(BorderlessButtonStyle())
.padding(.vertical, 4)
}
}
#Preview {
ContentView()
.frame(width: 320, height: 250)
}
有趣的是,当我在 iOS 上测试时,两种情况下都可以正常工作。但我需要适用于 macOS 的解决方案。
更新:
使用onTapGesture
而不是Button
确实可以改善情况,但会引入一个新错误。如果我最初点击该行,它最初可以正常工作,点击任意位置都会激活文本字段。但是在输入一些文本并按下回车键(或以任何方式失去焦点)后,如果我尝试点击 所在的行部分TextField
,它只有在点击现有文本时才有效......而不是点击它前面的空白处。
我将其添加.background(.red)
到了 HStack,并.background(.blue)
添加了一个屏幕截图来演示该问题。