更新:14 个月后,AppKit 发行说明中有一个有趣的注释:
您在选定列表行内编辑的文本字段现在具有正确的文本前景色。 (68545878)
现在,当将 TextField 放入列表中时,TextField 在第一次被选择时会在单击时获得焦点,但后续编辑尝试失败:列表行被选中,但 TextField 未获得焦点。
O/P:
在 beta6
SwiftUI
macOS(不是 iOS)应用程序中,我需要一个带有可编辑文本字段的 List
,但列表中的 TextField
不可编辑。如果我将 List
换成 Form
(或只是 VStack
),效果很好,但我需要它与 List
一起使用。有什么技巧可以告诉列表使字段可编辑吗?
import SwiftUI
struct ContentView: View {
@State var stringField: String = ""
var body: some View {
List { // works if this is VStack or Form
Section(header: Text("Form Header"), footer: Text("Form Footer")) {
TextField("Line 1", text: $stringField).environment(\.isEnabled, true)
TextField("Line 2", text: $stringField)
TextField("Line 3", text: $stringField)
TextField("Line 4", text: $stringField)
TextField("Line 5", text: $stringField)
}
}
}
}
我更新了项目以针对 MacOS 应用程序,并发现了您报告的错误。我已向 Apple 更新了此反馈,因为它确实似乎是一个错误(欢迎使用 Beta)。
FB7174245 - 嵌入列表中的 SwiftUI 文本字段不可编辑 当目标是 macOS 时
那么下面对状态和绑定的关注有什么意义呢?一个变量应该绑定到一个控件。这是一个工作示例。我将保留旧的答案,因为它通过完整的应用程序保存和检索 CoreData 的数据来推进示例。
import SwiftUI
struct ContentView: View {
@State var field1: String = ""
@State var field2: String = ""
@State var field3: String = ""
@State var field4: String = ""
@State var field5: String = ""
var body: some View {
List { // works if this is VStack or Form
Section(header: Text("Form Header"), footer: Text("Form Footer")) {
TextField("Line 1", text: $field1).environment(\.isEnabled, true)
TextField("Line 2", text: $field2)
TextField("Line 3", text: $field3)
TextField("Line 4", text: $field4)
TextField("Line 5", text: $field5)
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
顺便说一句 - 这适用于 Xcode Beta (11M392r) 和 MacOS Catalina - 10.15 测试版(19A546d)。
查看这个示例,其中包含一个可写入 CoreData 的可编辑文本字段,我正在 Github 上构建该文本字段。
看看@State和@Binding之间的区别,以便您 可以从内容视图外部操作数据。 (60 秒 视频)
struct ContentView: View {
// 1.
@State var name: String = ""
var body: some View {
VStack {
// 2.
TextField(" Enter some text", text: $name)
.border(Color.black)
Text("Text entered:")
// 3.
Text("\(name)")
}
.padding()
.font(.title)
}
}
查看以下答案以了解 @State 的适当用例 (所以回答)
以下代码只是一个实验,旨在了解 SwiftUI 中 List 的特性并展示替代方案。通过观察各种组合的输出,我了解到的是,列表视图的样式的结构方式是覆盖底层视图的默认行为,使其成为可选择的。这意味着 TextField 的作用完全不同。 TextField 是一个可聚焦的元素,我们可以在其中键入内容。此聚焦变量未连接到列表视图以协同工作。因此,列表会覆盖默认的可聚焦。因此不可能用 TextView 创建列表。但如果您需要,下一个最佳选择是 ScrollView 而不是 List,并显式地进行样式设置。检查以下代码以及两种方式。
import SwiftUI
struct ContentView: View {
@State private var arr = ["1","2","3"]
var body: some View {
HStack {
VStack {
List {
ForEach(self.arr.indices, id:\.self) {
TextField("", text: self.$arr[$0])
}
}
}
.frame(minWidth: 150, maxWidth: .infinity, minHeight: 300, maxHeight: .infinity)
VStack {
ScrollView {
ForEach(self.arr.indices, id:\.self) {
TextField("", text: self.$arr[$0])
.textFieldStyle(PlainTextFieldStyle())
.padding(2)
}
}
.padding(.leading, 5)
.padding(3)
}
.background(Color(NSColor.alternatingContentBackgroundColors[0]))
.frame(minWidth: 150, maxWidth: .infinity, minHeight: 300, maxHeight: .infinity)
}
}
}
extension NSTextField {
open override var focusRingType: NSFocusRingType {
get { .none }
set { }
}
}
是否获得焦点 - 如果您点击正确
在 macOS 应用程序中使用 Xcode 12.4 和 SwiftUI 2,我似乎遇到了同样的问题:无法使 TextEdit 在列表中工作。阅读此处并进行更多实验后,我意识到在我的情况下,TextField 确实可靠地获得焦点,但仅当您以正确的方式点击时。我认为并希望这不是它应有的工作方式,因此我发布了问题 macOS 上 SwiftUI 中的列表中的 TextField:编辑效果不佳,解释了我观察到的详细信息。
总结:在现有文本上精确单击确实可以获得焦点(在短暂的、烦人的延迟之后)。双击任意位置不会获得焦点。单击空白字段中的任意位置确实会获得焦点。
您可以在列表中使用 TextEditor 代替 TextField 以获得可编辑的文本字段。
TextEditor(text: $strings)
.font(.body)
.cornerRadius(5)
.shadow(color: Color.black.opacity(0.18), radius: 0.8, y: 1)
.frame(height: 20)
这样您将在 TextEditor 和 TextField 之间获得相似的外观。
放置在 SwiftUI
TextField
(启用选择)内的 List
从 macOS 13.5.1 开始似乎具有正确的编辑行为。当您单击选定的行时,TextField
变为可编辑。剪辑的长文本的水平“滚动”也可以正常工作。这些功能在 macOS 12.6.8 上无法正常工作。
但是,
ContextMenu
的行为不正确。在选定的 TextField
上右键单击(例如,用两根手指点击触控板)不会调出附加到 TextField
(或 List
)的上下文菜单,而是错误地使 TextField
可编辑并带来在 TextField
内选择所选文本的系统文本选择菜单(例如查找、翻译、搜索、剪切、复制、粘贴、共享等)。按住 Control 键并单击 TextField
不会弹出任何菜单。相反,如果选择了 TextField
,则会将其置于编辑模式。如果按住 Control 键单击未选定的行/TextField
,则会选择该 TextField
,而不是显示 ContextMenu
。
感觉从事 SwiftUI 的工程师对于 macOS 应该如何表现没有太多经验。