ScrollView / LazyVGrid 中 SwiftUI 中的 EditButton()
EditButton() in SwiftUI inside a ScrollView / LazyVGrid
SwiftUI(Xcode 12.5 beta 3)中的 EditButton() 似乎存在各种问题。
在我的代码中,一切正常,直到我用 ScrollView 替换了 List 并添加了 LazyVGrid。现在,当用户点击 EditButton 时,不会激活 EditMode。
有什么解决方法吗? UI 要求有 2 列,虽然我可以使用列表,但我更喜欢 ScrollView 的外观。我已经尝试了很多东西......将 ForEach 放在一个部分并将 EditButton 放在 header 中,用手动按钮替换它......不幸的是 none 它们似乎工作:-(
非常感谢您的任何想法或任何其他人为解决此问题所做的任何事情。
struct Home: View {
@Environment(\.managedObjectContext) private var viewContext
@FetchRequest(entity: Cars.entity(), sortDescriptors: []) var cars: FetchedResults<Cars>
private var columns: [GridItem] = [
GridItem(.flexible()),
GridItem(.flexible())
]
var body: some View {
NavigationView {
ScrollView {
if cars.count > 0 {
LazyVGrid(
columns: columns) {
ForEach(cars) { n in
Text("hello")
}
.onDelete(perform: deleteCars)
}
}
else {
Text("You have no cars.")
}
}
.navigationBarItems(leading: EditButton())
}
}
func deleteCars(at offsets: IndexSet) {
for offset in offsets {
let cars = cars[offset]
viewContext.delete(cars)
}
try? viewContext.save()
}
}
尝试 1
阅读下面 Asperi 的评论后,我将以下内容添加到 ScrollView 以手动创建按钮、触发 EditMode 和删除项目。现在我在 deleteCars
行收到一个新错误:“Initializer 'init(_:)' requires that 'FetchedResults.Element' (aka 'Cars') conform to 'Sequence'”.
看起来我真的很接近,但仍在挣扎 - 谁能帮助我完成最后的部分?非常感谢!
@State var isEditing = false
...
ScrollView {
if cars.count > 0 {
LazyVGrid(
columns: columns) {
ForEach(cars) { n in
Text("hello")
Button(action : {
deleteCars(at: IndexSet(n))
print("item deleted")
})
{Text("\(isEditing ? "Delete me" : "not editing")")}
}
.onDelete(perform: deleteCars)
.environment(\.editMode, .constant(self.isEditing ? EditMode.active : EditMode.inactive)).animation(Animation.spring())
}
}
else {
Text("You have no cars.")
}
Button(action: {
self.isEditing.toggle()
}) {
Text(isEditing ? "Done" : "Edit")
.frame(width: 80, height: 40)
}
}
TLDR:手动创建一个 EditButton 并将其直接添加到 ForEach 循环中。确保 ForEach 数组指定了索引。
好的,随着上述尝试 1 的进展,终于找到了答案...通过将 .indices 添加到 ForEach 循环中的数组来解决。完整内容如下:
struct Home: View {
@Environment(\.managedObjectContext) private var viewContext
@FetchRequest(entity: Cars.entity(), sortDescriptors: []) var cars: FetchedResults<Cars>
@State var isEditing = false
private var columns: [GridItem] = [
GridItem(.flexible()),
GridItem(.flexible())
]
var body: some View {
NavigationView {
VStack{
ScrollView {
if cars.count > 0 {
LazyVGrid(
columns: columns) {
ForEach(cars.indices, id: \.self) { n in
Text("hello")
Button(action : {
deleteCars(at: [n])
print("item deleted")
})
{Text("\(isEditing ? "Delete me" : "not editing")")}
}
}
.environment(\.editMode, .constant(self.isEditing ? EditMode.active : EditMode.inactive)).animation(Animation.spring())
}
}
else {
Text("You have no cars.")
}
}
.navigationBarItems(leading: Button(action: {
self.isEditing.toggle()
}) {
Text(isEditing ? "Done" : "Edit")
.frame(width: 80, height: 40)
}
)
}
}
func deleteCars(at offsets: IndexSet) {
for offset in offsets {
let cars = cars[offset]
viewContext.delete(cars)
}
try? viewContext.save()
}
}
我相信有很多方法可以优化它(代码和 question/answer 的编写方式,所以请随时提出建议。
SwiftUI(Xcode 12.5 beta 3)中的 EditButton() 似乎存在各种问题。
在我的代码中,一切正常,直到我用 ScrollView 替换了 List 并添加了 LazyVGrid。现在,当用户点击 EditButton 时,不会激活 EditMode。
有什么解决方法吗? UI 要求有 2 列,虽然我可以使用列表,但我更喜欢 ScrollView 的外观。我已经尝试了很多东西......将 ForEach 放在一个部分并将 EditButton 放在 header 中,用手动按钮替换它......不幸的是 none 它们似乎工作:-(
非常感谢您的任何想法或任何其他人为解决此问题所做的任何事情。
struct Home: View {
@Environment(\.managedObjectContext) private var viewContext
@FetchRequest(entity: Cars.entity(), sortDescriptors: []) var cars: FetchedResults<Cars>
private var columns: [GridItem] = [
GridItem(.flexible()),
GridItem(.flexible())
]
var body: some View {
NavigationView {
ScrollView {
if cars.count > 0 {
LazyVGrid(
columns: columns) {
ForEach(cars) { n in
Text("hello")
}
.onDelete(perform: deleteCars)
}
}
else {
Text("You have no cars.")
}
}
.navigationBarItems(leading: EditButton())
}
}
func deleteCars(at offsets: IndexSet) {
for offset in offsets {
let cars = cars[offset]
viewContext.delete(cars)
}
try? viewContext.save()
}
}
尝试 1
阅读下面 Asperi 的评论后,我将以下内容添加到 ScrollView 以手动创建按钮、触发 EditMode 和删除项目。现在我在 deleteCars
行收到一个新错误:“Initializer 'init(_:)' requires that 'FetchedResults.Element' (aka 'Cars') conform to 'Sequence'”.
看起来我真的很接近,但仍在挣扎 - 谁能帮助我完成最后的部分?非常感谢!
@State var isEditing = false
...
ScrollView {
if cars.count > 0 {
LazyVGrid(
columns: columns) {
ForEach(cars) { n in
Text("hello")
Button(action : {
deleteCars(at: IndexSet(n))
print("item deleted")
})
{Text("\(isEditing ? "Delete me" : "not editing")")}
}
.onDelete(perform: deleteCars)
.environment(\.editMode, .constant(self.isEditing ? EditMode.active : EditMode.inactive)).animation(Animation.spring())
}
}
else {
Text("You have no cars.")
}
Button(action: {
self.isEditing.toggle()
}) {
Text(isEditing ? "Done" : "Edit")
.frame(width: 80, height: 40)
}
}
TLDR:手动创建一个 EditButton 并将其直接添加到 ForEach 循环中。确保 ForEach 数组指定了索引。
好的,随着上述尝试 1 的进展,终于找到了答案...通过将 .indices 添加到 ForEach 循环中的数组来解决。完整内容如下:
struct Home: View {
@Environment(\.managedObjectContext) private var viewContext
@FetchRequest(entity: Cars.entity(), sortDescriptors: []) var cars: FetchedResults<Cars>
@State var isEditing = false
private var columns: [GridItem] = [
GridItem(.flexible()),
GridItem(.flexible())
]
var body: some View {
NavigationView {
VStack{
ScrollView {
if cars.count > 0 {
LazyVGrid(
columns: columns) {
ForEach(cars.indices, id: \.self) { n in
Text("hello")
Button(action : {
deleteCars(at: [n])
print("item deleted")
})
{Text("\(isEditing ? "Delete me" : "not editing")")}
}
}
.environment(\.editMode, .constant(self.isEditing ? EditMode.active : EditMode.inactive)).animation(Animation.spring())
}
}
else {
Text("You have no cars.")
}
}
.navigationBarItems(leading: Button(action: {
self.isEditing.toggle()
}) {
Text(isEditing ? "Done" : "Edit")
.frame(width: 80, height: 40)
}
)
}
}
func deleteCars(at offsets: IndexSet) {
for offset in offsets {
let cars = cars[offset]
viewContext.delete(cars)
}
try? viewContext.save()
}
}
我相信有很多方法可以优化它(代码和 question/answer 的编写方式,所以请随时提出建议。