具有多个编辑按钮的 SwiftUI 表单

Posted

技术标签:

【中文标题】具有多个编辑按钮的 SwiftUI 表单【英文标题】:SwiftUI Form with Multiple EditButtons 【发布时间】:2021-05-15 18:26:24 【问题描述】:

试图让Form 有多个部分,每个Section 都有自己的EditButton

    如何在不触发Form 中的所有部分的情况下触发Section 进入“编辑模式”,如随附的gif 所示。

    如何跟踪某个Section中的EditButton是否被触发,从而Button出现在那个Section中。

我使用了这两个来源的代码: developer.apple.com, ***.com

代码如下:

import SwiftUI

struct ContentView: View 
    @Environment(\.editMode) private var editMode
    @State private var section1: [String] = ["Item 1", "Item 2"]
    @State private var section2: [String] = ["Item 3", "Item 4"]
    @State private var isEditingSection1 = false
    @State private var isEditingSection2 = false
    
    var body: some View 
        Form 
            // Section 1
            Section (header:
                        EditButton().frame(maxWidth: .infinity, alignment: .trailing)
                        .overlay(
                            HStack 
                                Image(systemName: "folder")
                                    .foregroundColor(Color.gray)
                            Text("Section 1")
                                .textCase(.none)
                                .foregroundColor(Color.gray)
                            , alignment: .leading)
                        .foregroundColor(.blue)) 
                ForEach(section1, id: \.self)  item in
                   Text(item)
                
                .onDelete(perform: deleteSection1)
                .onMove(perform: moveSection1)
                
                // Add item option
                if editMode?.wrappedValue.isEditing ?? true /*isEditingSection1*/ 
                    Button ("Add Item") 
                        // add action
                    
                
            
            
            // Section 2
            Section (header:
                        EditButton().frame(maxWidth: .infinity, alignment: .trailing)
                        .overlay(
                            HStack 
                                Image(systemName: "tray")
                                    .foregroundColor(Color.gray)
                                Text("Section 2")
                                    .textCase(.none)
                                    .foregroundColor(Color.gray)
                            , alignment: .leading)
                        .foregroundColor(.blue)) 
                ForEach(section2, id: \.self)  item in
                    Text(item)
                
                .onDelete(perform: deleteSection2)
                .onMove(perform: moveSection2)
                
                // Add item option
                if editMode?.wrappedValue.isEditing ?? true /*isEditingSection2*/ 
                    Button ("Add Item") 
                        // add action
                    
                
            
            
        
    
    
    func deleteSection1(at offsets: IndexSet) 
        section1.remove(atOffsets: offsets)
    
    
    func moveSection1(from source: IndexSet, to destination: Int) 
        section1.move(fromOffsets: source, toOffset: destination)
    
    
    func deleteSection2(at offsets: IndexSet) 
        section2.remove(atOffsets: offsets)
    
    
    func moveSection2(from source: IndexSet, to destination: Int) 
        section2.move(fromOffsets: source, toOffset: destination)
    


struct ContentView_Previews: PreviewProvider 
    static var previews: some View 
        ContentView()
    

【问题讨论】:

【参考方案1】:

没有内置的东西可以为每个部分设置不同的编辑模式。

但您可以显式使用它来设置编辑模式并禁用/启用每行的删除和移动操作。

这是可能的解决方案演示。

为此,您需要首先使用绑定 bool 值创建自己的 EditButton。

struct EditButton: View 
    @Binding var isEditing: Bool

    var body: some View 
        Button(isEditing ? "DONE" : "EDIT") 
            withAnimation 
                isEditing.toggle()
            
        
    

现在你的Form 视图是。

struct ContentViewEditModeDemo: View 
    @State private var section1: [String] = ["Item 1", "Item 2"]
    @State private var section2: [String] = ["Item 3", "Item 4"]
    @State private var isEditingSection1 = false
    @State private var isEditingSection2 = false
    
    private var isEditingOn: Bool  //<=== Here
        isEditingSection1 || isEditingSection2
    
    
    var body: some View 
        Form 
            // Section 1
            Section (header:
                        EditButton(isEditing: $isEditingSection1).frame(maxWidth: .infinity, alignment: .trailing) //<=== Here
                        .overlay(
                            HStack 
                                Image(systemName: "folder")
                                    .foregroundColor(Color.gray)
                            Text("Section 1")
                                .textCase(.none)
                                .foregroundColor(Color.gray)
                            , alignment: .leading)
                        .foregroundColor(.blue)) 
                ForEach(section1, id: \.self)  item in
                   Text(item)
                
                .onDelete(perform: deleteSection1)
                .onMove(perform: moveSection1)
                .moveDisabled(!isEditingSection1) //<=== Here
                .deleteDisabled(!isEditingSection1) //<=== Here

                // Add item option
                if isEditingSection1  //<=== Here
                    Button ("Add Item") 
                        // add action
                    
                
            
            
            // Section 2
            Section(header:
                        EditButton(isEditing: $isEditingSection2).frame(maxWidth: .infinity, alignment: .trailing) //<=== Here
                        .overlay(
                            HStack 
                                Image(systemName: "tray")
                                    .foregroundColor(Color.gray)
                                Text("Section 2")
                                    .textCase(.none)
                                    .foregroundColor(Color.gray)
                            , alignment: .leading)
                        .foregroundColor(.blue)) 
                ForEach(section2, id: \.self)  item in
                    Text(item)
                
                .onDelete(perform: deleteSection1)
                .onMove(perform: moveSection1)
                .moveDisabled(!isEditingSection2) //<=== Here
                .deleteDisabled(!isEditingSection2) //<=== Here
                
                // Add item option
                if isEditingSection2  //<=== Here
                    Button ("Add Item") 
                        // add action
                    
                
            
        .environment(\.editMode, isEditingOn ? .constant(.active) : .constant(.inactive)) //<=== Here
    
    
    func deleteSection1(at offsets: IndexSet) 
        section1.remove(atOffsets: offsets)
    
    
    func moveSection1(from source: IndexSet, to destination: Int) 
        section1.move(fromOffsets: source, toOffset: destination)
    
    
    func deleteSection2(at offsets: IndexSet) 
        section2.remove(atOffsets: offsets)
    
    
    func moveSection2(from source: IndexSet, to destination: Int) 
        section2.move(fromOffsets: source, toOffset: destination)
    

【讨论】:

以上是关于具有多个编辑按钮的 SwiftUI 表单的主要内容,如果未能解决你的问题,请参考以下文章

具有 10 多个项目的 SwiftUI 菜单按钮

如何在 swift UI 中单击按钮时从 swift UI 导航到情节提要?

Swiftui 按钮动作功能

用于完成按钮的文本字段的 swift ui 扩展

SwiftUI 列出多个自定义行编辑选项

具有多个提交按钮或多个表单的表单[重复]