如何在不使用swiftUI附带的幻灯片删除的情况下创建自定义删除按钮我没有使用列表,只是使用foreach循环

Posted

技术标签:

【中文标题】如何在不使用swiftUI附带的幻灯片删除的情况下创建自定义删除按钮我没有使用列表,只是使用foreach循环【英文标题】:How to create a custom delete button without using the slide to delete that comes with swiftUI I am not using list, just using a foreach loop 【发布时间】:2020-09-10 06:47:07 【问题描述】:

由于 onDelete 和 onMove 是 List/form 的功能,当我有没有它们的自定义界面时,我无法使用它们。我在 ForEach 中使用了 VStack。我对 swiftUI 很陌生,不确定如何为 onDelete 和 onMove 实现自定义代码。

这是我的代码:

struct Trying: View 
    @State private var numbers = [0,1,2,3,4,5,6,7,8,9]
    var body: some View 
        NavigationView 
            VStack (spacing: 10) 
                ForEach(numbers, id: \.self)  number in
                    VStack 
                        Text("\(number)")
                    
                    .frame(width: 50, height: 50)
                    .background(Color.red)
                .onDelete(perform: removeRows)
            
            .navigationTitle("Trying")
            .navigationBarItems(trailing: EditButton())
        
    
    
    func removeRows(at offsets: IndexSet) 
        numbers.remove(atOffsets: offsets)
    

现在的工作方式:

【问题讨论】:

【参考方案1】:

这是实现自定义删除的可能方法的简单演示(当然,由于拖放,移动会更复杂,但想法是相同的)。使用 Xcode 12 / ios 14 测试。

struct DemoCustomDelete: View 
    @State private var numbers = [0,1,2,3,4,5,6,7,8,9]
    var body: some View 
        NavigationView 
            VStack (spacing: 10) 
                ForEach(numbers, id: \.self)  number in
                    VStack 
                        Text("\(number)")
                    
                    .frame(width: 50, height: 50)
                    .background(Color.red)
                    .overlay(
                        DeleteButton(number: number, numbers: $numbers, onDelete: removeRows)
                    , alignment: .topTrailing)
                .onDelete(perform: removeRows)
            
            .navigationTitle("Trying")
            .navigationBarItems(trailing: EditButton())
        
    

    func removeRows(at offsets: IndexSet) 
        withAnimation 
            numbers.remove(atOffsets: offsets)
        
    


struct DeleteButton: View 
    @Environment(\.editMode) var editMode

    let number: Int
    @Binding var numbers: [Int]
    let onDelete: (IndexSet) -> ()

    var body: some View 
        VStack 
            if self.editMode?.wrappedValue == .active 
                Button(action: 
                    if let index = numbers.firstIndex(of: number) 
                        self.onDelete(IndexSet(integer: index))
                    
                ) 
                    Image(systemName: "minus.circle")
                
                .offset(x: 10, y: -10)
            
        
    

【讨论】:

-查看您的解决方案,我想知道这是否适用于 CoreData?我有一个lazyHGrid,它显示了FetchRequest 的结果。我无法弄清楚如何获得有效的删除功能。在我切换到lazyHGrid之前,我使用的是一个简单的列表,我可以通过 - private func deleteEvent(offsets: IndexSet) withAnimation offsets.map events[$0] .forEach(moc.delete) do try moc. save() catch let nsError = error as NSError fatalError("未解决的错误 (nsError), (nsError.userInfo)") 【参考方案2】:

根据@Asperi 的回答,我只是将其概括为接受任何Equatable 序列。

struct DeleteButton<T>: View where T: Equatable 
  @Environment(\.editMode) var editMode

  let number: T
  @Binding var numbers: [T]
  let onDelete: (IndexSet) -> ()

  var body: some View 
    VStack 
        if self.editMode?.wrappedValue == .active 
            Button(action: 
                if let index = numbers.firstIndex(of: number) 
                    self.onDelete(IndexSet(integer: index))
                
            ) 
                Image(systemName: "minus.circle")
            
            .offset(x: 10, y: -10)
        
    
  

【讨论】:

【参考方案3】:

我最近需要删除一行,但我无法使用 LIST。相反,我有一个滚动视图......但我能够实现编辑以模拟相同的 onDelete 行为,就好像它是一个列表一样。最初我无法让我的代码工作。直到我仔细检查了我的实现并进行了实验,我才偶然发现我的工作原理。我正在为 iPad 编写代码,以便我的 NavigationView 使用,

.navigationViewStyle(StackNavigationViewStyle())

一旦我将它添加到结构的 NavigationView 中,当您单击 EditButton 时,它会将 editMode?.wrappedValue 激活为 .active / .inactive

下面是我对上面代码示例的实现...

struct Trying: View 
    
    @State var num: Int = 0
    @Environment(\.editMode) var editMode
    
    @State private var numbers = [0,1,2,3,4,5,6,7,8,9]
    var body: some View 
        NavigationView 

            VStack 
                ForEach(numbers, id: \.self)  number in
                    HStack 
                        if editMode?.wrappedValue == .active 
                            Button(action:  num = number
                                removeRows(numbr: num)
                            , label: 
                                Image(systemName: "minus.circle.fill")
                                    .foregroundColor(.red)
                            )
                         // END IF editMode?wrappedValue == .active
                        Text("\(number)")
                            .frame(width: 50, height: 50)
                            .background(Color.red)
                    

                
//                .onDelete(perform: removeRows)
            

            .navigationTitle("Trying")
            .navigationBarItems(trailing: EditButton())
        
        // FOR SOME REASON THIS ALLOWS THE EditButton() to activate editMode  without a LIST being present.
        .navigationViewStyle(StackNavigationViewStyle())
    
    
    func removeRows(numbr: Int) 
        print("removing \(numbr)")
    


看起来像:

【讨论】:

以上是关于如何在不使用swiftUI附带的幻灯片删除的情况下创建自定义删除按钮我没有使用列表,只是使用foreach循环的主要内容,如果未能解决你的问题,请参考以下文章

SwiftUI 如何在不使用 List 的情况下从 @ObservedObject ViewModel 获取 Firebase 数据

如何在不使当前视图颤动的情况下实现这种幻灯片效果

如何在不继承 SwiftUI 中其他已定义视图的情况下制作正文,苹果最初是如何做到的?

在不影响外框的情况下使用 SwiftUI GeometryReader?

在不使用导航链接的情况下获取 SwiftUI 列表中的选定项目

Firestore 在不重新加载应用程序的情况下不更新 SwiftUI 网格