SwiftUI 上带有 TextField 的可删除表
Posted
技术标签:
【中文标题】SwiftUI 上带有 TextField 的可删除表【英文标题】:Deletable Table with TextField on SwiftUI 【发布时间】:2019-11-18 07:29:50 【问题描述】:环境
Xcode 11.2.1 (11B500)问题
为了在 SwiftUI 上使用 TextField 实现可编辑的 teble,我使用了ForEach(0..<items.count)
来处理索引。
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
when delete item
????已从动物中删除,并且 ForEach 循环似乎运行了两次,即使 animals.count 为 1。
(lldb) po animals.count
1
(lldb) po animals
▿ 1 element
- 0 : "????"
请给我关于 Foreach 和 TextField 组合的建议。 谢谢。
【问题讨论】:
【参考方案1】:好的,原因在于使用的 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()
【讨论】:
该死的,你这次的速度更快 ;) 哦……我们在竞争吗? :) 这个答案太棒了!它也适用于复杂类型! “动态容器”是什么意思,我很难理解为什么这个解决方案有效......【参考方案2】:这是因为 editbutton 在您的列表中。将它放在外面或更好的导航栏中。
【讨论】:
不,这无济于事。以上是关于SwiftUI 上带有 TextField 的可删除表的主要内容,如果未能解决你的问题,请参考以下文章
键盘出现/消失时调整带有 TextField 的 SwiftUI 列表