您可以像 ToolbarContent 的命名块一样使用闭包吗 - ToolbarItem

Can you use closure like a named block for ToolbarContent - ToolbarItem

我将 ToolbarContent 与 ToolbarItem 结合使用,以便在多个视图中拥有一致的工具栏...工具栏看起来像:

struct ToolBarCancelDeleteAdd: ToolbarContent {
    
    @Binding var deletePressed: Bool
    let cancel: () -> Void
    let deleting: () -> Void
    let adding: () -> Void
    
    var body: some ToolbarContent {
        
        ToolbarItemGroup(placement: .cancellationAction) {
            Button("Cancel", action: cancel )
        }
        
        ToolbarItemGroup(placement: .confirmationAction) {
            if deletePressed {
                Button(action: deleting, label:{Text("Done")})
            } else {
                Button(action: deleting, label:{Text("Delete")})
            }
            Button(action: adding, label: {Image(systemName: "plus")})
        }
    }

在我看来,我正在添加工具栏并提供所需的关闭信息..

        .navigationBarBackButtonHidden(true)
        .navigationTitle("Budget Descriptions")
        .toolbar() { 
            ToolBarCancelDeleteAdd(deletePressed: $deletePressed){
                if self.editMode?.wrappedValue == .active {
                    self.editMode?.wrappedValue = .inactive
                    deletePressed.toggle()
                }
                self.presentationMode.wrappedValue.dismiss()
            }   deleting: {
                if self.editMode?.wrappedValue == .inactive {
                    self.editMode?.wrappedValue = .active
                    deletePressed.toggle()
                } else {
                    self.editMode?.wrappedValue = .inactive
                    deletePressed.toggle()
                }
            } adding: {
                if self.editMode?.wrappedValue == .active {
                    self.editMode?.wrappedValue = .inactive
                }
                self.isAdding.toggle()
            }
        } // END OF TOOLBAR

这一切都很好,我很高兴......除了我在多个视图中执行此代码,如果我需要调整它,我必须转到多个视图来调整它。如果我能像使用 ViewBuilder 对某些视图所做的那样命名此闭包内容,那就太好了。这样我就可以用某种方式命名闭包内容。就像...

        .navigationBarBackButtonHidden(true)
        .navigationTitle("Budget Descriptions")
        .toolbar() { 
            ToolBarCancelDeleteAdd(deletePressed: $deletePressed){
                   CancelContent()
            }   deleting: {
                   DeleteContent()            
            } adding: {
                   AddingContent()
            }
        } // END OF TOOLBAR

为什么不制作一个包含方法的class

class ToolbarViewModel: ObservableObject {
    func cancelContent(deletePressed: inout Bool, editMode: inout EditMode) {
        if editMode == .active {
            editMode = .inactive
            deletePressed.toggle()
        }
    }

    func deleteContent(deletePressed: inout Bool, editMode: inout EditMode) {
        if editMode == .inactive {
            editMode = .active
            deletePressed.toggle()
        } else {
            editMode = .inactive
            deletePressed.toggle()
        }
    }

    func addingContent(isAdding: inout Bool, editMode: inout EditMode) {
        if editMode == .active {
            editMode = .inactive
        }
        isAdding.toggle()
    }
}

然后你可以在通话时使用它

struct ContentView: View {
    @Environment(\.presentationMode) var presentationMode
    @StateObject var toolbarViewModel = ToolbarViewModel()
    @State private var deletePressed = false
    @State private var isAdding = false
    @State private var editMode: EditMode = .active

    var body: some View {
        NavigationView {
            VStack {
                Text("Hello, world!")
                    .padding()
            }
            .toolbar {
                ToolBarCancelDeleteAdd(deletePressed: $deletePressed) {
                    toolbarViewModel.deleteContent(deletePressed: &deletePressed, editMode: &editMode)
                    presentationMode.wrappedValue.dismiss()
                } deleting: {
                    toolbarViewModel.deleteContent(deletePressed: &deletePressed, editMode: &editMode)
                } adding: {
                    toolbarViewModel.addingContent(isAdding: &isAdding, editMode: &editMode)
                }
            }
        }
    }
}
enum EditMode {
    case active, inactive
}

在上面 Nigel Gee 的建议和 SwiftUI 实验室的 Javier 的帮助下,我有了最终的解决方案来实现我的目标,即能够将代码注入我的 .toolbar。看起来像:

class ToolbarViewModel: ObservableObject {
    
    func cancelContent(editMode: Binding<EditMode>?) {
    
        if editMode?.wrappedValue == .active {
            editMode?.wrappedValue = .inactive
        }
    }

    func deleteContent(deletePressed: inout Bool, editMode: Binding<EditMode>?) {
        
        if editMode?.wrappedValue == .inactive {
            editMode?.wrappedValue = .active
        } else {
            editMode?.wrappedValue = .inactive
        }
    }

    func addingContent(isAdding: inout Bool, editMode: Binding<EditMode>?) {

        if editMode?.wrappedValue == .active {
            editMode?.wrappedValue = .inactive
        }
        isAdding.toggle()
    }
}

在我看来,我声明:


    @Environment(\.editMode) var editMode: Binding<EditMode>?

    @StateObject var toolbarViewModel = ToolbarViewModel()

工具栏如下所示:

.toolbar {
    ToolBarCancelDeleteAdd() {
        toolbarViewModel.cancelContent(editMode: editMode)
        presentationMode.wrappedValue.dismiss()
    } deleting: {
        toolbarViewModel.deleteContent(deletePressed: &deletePressed, editMode: editMode)
    } adding: {
        toolbarViewModel.addingContent(isAdding: &isAdding, editMode: editMode)
    }
} // END OF TOOLBAR