swift - SwiftUI 上带有 TextField 的可删除表
问题描述
环境
- Xcode 11.2.1 (11B500)
问题
为了在 SwiftUI 上使用 TextField 实现可编辑的 teble,我曾经ForEach(0..<items.count)
处理 index.html。
import SwiftUI
struct DummyView: View {
@State var animals: [String] = ["", ""]
var body: some View {
List {
EditButton()
ForEach(0..<animals.count) { i in
TextField("", text: self.$animals[i])
}
}
}
}
但是,如果将表更改为可删除,则会出现问题。
import SwiftUI
struct DummyView: View {
@State var animals: [String] = ["", ""]
var body: some View {
List {
EditButton()
ForEach(0..<animals.count) { i in
TextField("", text: self.$animals[i]) // Thread 1: Fatal error: Index out of range
}
.onDelete { indexSet in
self.animals.remove(atOffsets: indexSet) // Delete "" from animals
}
}
}
}
Thread 1: Fatal error: Index out of range
删除项目时
已从动物中删除,并且 ForEach 循环似乎运行了两次,即使 animals.count 为 1。
(lldb) po animals.count
1
(lldb) po animals
▿ 1 element
- 0 : ""
请给我关于 Foreach 和 TextField 组合的建议。
谢谢。
解决方案
好的,原因在于使用的 ForEach 构造函数的文档(如您所见,范围是恒定的,因此 ForEach 获取初始范围并保持它):
/// Creates an instance that computes views on demand over a *constant*
/// range.
///
/// This instance only reads the initial value of `data` and so it does not
/// need to identify views across updates.
///
/// To compute views on demand over a dynamic range use
/// `ForEach(_:id:content:)`.
public init(_ data: Range<Int>, @ViewBuilder content: @escaping (Int) -> Content)
所以解决方案是提供动态容器。您可以在下面找到可能的方法的演示。
完整的模块代码
import SwiftUI
struct DummyView: View {
@State var animals: [String] = ["", ""]
var body: some View {
VStack {
HStack {
EditButton()
Button(action: { self.animals.append("Animal \(self.animals.count + 1)") }, label: {Text("Add")})
}
List {
ForEach(animals, id: \.self) { item in
EditorView(container: self.$animals, index: self.animals.firstIndex(of: item)!, text: item)
}
.onDelete { indexSet in
self.animals.remove(atOffsets: indexSet) // Delete "" from animals
}
}
}
}
}
struct EditorView : View {
var container: Binding<[String]>
var index: Int
@State var text: String
var body: some View {
TextField("", text: self.$text, onCommit: {
self.container.wrappedValue[self.index] = self.text
})
}
}
struct TestForEachCapture_Previews: PreviewProvider {
static var previews: some View {
DummyView()
}
}
推荐阅读
- vba - 无法在 VBA 代码中添加信任链
- laravel - 在 Laravel 中存储复选框和文本区域的最佳实践
- gradle - 有没有办法让 gradle 项目零配置?
- blazor-server-side - Blazor Server - 如何禁用身份注册页面
- testing - TestCafe-BrowserStack 脚本挂起并且在测试页面抛出 500 或“内存不足”等一般错误时不会终止
- c# - Webview 5.11 从本地 Intranet 站点呈现空白窗口,C# WPF
- c# - 如何确定多边形(三角形)的旋转点?
- php - 如何在我的网站上嵌入 Facebook 视频
- file - 如何使用sed提取一个浮点数
- python - spaCy BERT 词典