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

2024-04-21

试图有一个Form有多个部分,每个部分Section与它自己的EditButton.

  1. 如何触发Section进入“编辑模式”而不触发中的所有部分Form,如所附 gif 所示。

  2. 如何追踪EditButton在一定的Section被触发,以便Button出现在那个Section.

我使用了这两个来源的代码:开发者.apple.com https://developer.apple.com/forums/thread/125823, stackoverflow.com https://stackoverflow.com/questions/63339565/swiftui-editbutton-in-hstack-not-activating-edit-mode

这是代码:

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()
    }
}

iOS 16 更新:

我希望我知道why,但在 iOS 16 中你必须像这样表达布尔表达式。

.deleteDisabled(isEditingSection2)
.deleteDisabled((isEditingSection2 || isEditingSection3))
// Etc...

在 iOS 15.5 中,你可以选择其中任何一个。

.deleteDisabled(!isEditingSection1)
// Or...
.deleteDisabled(isEditingSection2)

这是一个完整的ContentView and EditButton显示这个。我添加了第三部分来帮助演示如何在内部应用布尔 OR 逻辑.deleteDisabled and .moveDisabled.

import SwiftUI

struct ContentView: View {
    @State private var section1: [String] = ["Item 1", "Item 2"]
    @State private var section2: [String] = ["Item 3", "Item 4"]
    @State private var section3: [String] = ["Item 5", "Item 6"]
    @State private var isEditingSection1 = false
    @State private var isEditingSection2 = false
    @State private var isEditingSection3 = false
    
    private var isEditingOn: Bool { //<=== Here
        isEditingSection1 || isEditingSection2 || isEditingSection3
    }
    
    var body: some View {
        Form {
            // Section 1
            Section (header:
                EditButton(isEditing: $isEditingSection1, printBools: printBools)
                .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)
                        .moveDisabled(isEditingSection2 || isEditingSection3) //<=== Here
                        .deleteDisabled((isEditingSection2 || isEditingSection3)) //<=== Here
                        
                        // BIG NOTE!!
                        // This works in iOS 15.5, but not iOS 16:  `.deleteDisabled(!isEditingSection1)`
                        // This works in both 15.5 and 16.0.  Why??? `.deleteDisabled(isEditingSection2 || isEditingSection3)`
                        
                        // Add item option
                        if isEditingSection1 { //<=== Here
                            Button ("Add Item") {
                                // add action
                            }
                        }
                    }
            
            // Section 2
            Section(header:
                EditButton(isEditing: $isEditingSection2, printBools: printBools)
                .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)
                        .moveDisabled(isEditingSection1 || isEditingSection3) //<=== Here
                        .deleteDisabled(isEditingSection1 || isEditingSection3) //<=== Here
                        
                        // Add item option
                        if isEditingSection2 { //<=== Here
                            Button ("Add Item") {
                                // add action
                            }
                        }
                    }
            
            // Section 3
            Section(header:
                EditButton(isEditing: $isEditingSection3, printBools: printBools)
                .frame(maxWidth: .infinity, alignment: .trailing)
                .overlay(
                    HStack {
                        Image(systemName: "tray")
                            .foregroundColor(Color.gray)
                        Text("Section 3")
                            .textCase(.none)
                            .foregroundColor(Color.gray)
                    }, alignment: .leading)
                    .foregroundColor(.blue)) {
                        ForEach(section3, id: \.self) { item in
                            Text(item)
                        }
                        .onDelete(perform: deleteSection3)
                        .onMove(perform: moveSection3)
                        .moveDisabled(isEditingSection1 || isEditingSection2) //<=== Here
                        .deleteDisabled(isEditingSection1 || isEditingSection2) //<=== Here
                        
                        // Add item option
                        if isEditingSection3 { //<=== 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)
    }
    
    func deleteSection3(at offsets: IndexSet) {
        section3.remove(atOffsets: offsets)
    }
    
    func moveSection3(from source: IndexSet, to destination: Int) {
        section3.move(fromOffsets: source, toOffset: destination)
    }
    
    
    func printBools() {
//        let _ = print("isEditingSection1 = \(isEditingSection1)")
//        let _ = print("isEditingSection2 = \(isEditingSection2)")
    }
}


struct EditButton: View {
    @Binding var isEditing: Bool
    
    let printBools: () -> Void

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


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

注意逻辑上这里,两个表达式!isEditingSection1 and isEditingSection2 || isEditingSection3当我们考虑如何在这里使用它们时,它们是等效的。

isEditingSection1 ! isEditingSection1 isEditingSection2 OR isEditingSection3
true false false
false true true, if editing another section. Otherwise false.
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

具有多个编辑按钮的 SwiftUI 表单 的相关文章

  • 如何在 SwiftUI TextField 中将文本加粗?

    从 Xcode 11 2 1 开始 SwiftUI 中的文本字段没有内置的字体粗细修饰符 我们如何在不将 UITextField 扩展为 UIViewRepresentable 的情况下引入 font weight 使用与 SwiftUI
  • 在 SwiftUI 中正确组合 TabView 与 PageTabViewStyle、NavigationView 和 ScrollView

    我正在开发一个将 TabView 与 PageTabViewStyle NavigationView 和 ScrollView 结合在一起的 UI 向下滚动时 我希望 NavigationView 的标题能够调整并变小 但当 ScrollV
  • 在视图之间传递变量 SwiftUI

    再次基本问题 我想让变量 anytext 对于我要添加的所有未来视图都可见且可访问 在我的例子中 变量将是String 如果是的话 程序会改变吗 Float 我怎样才能将其另存为全局变量 如果我重新启动应用程序 变量会自行删除吗 如何保存即
  • SceneDelegate 和 AppDelegate 之间的区别

    在我的 SwiftUI 项目中我看到AppDelegate文件以及SceneDelegate file 它们之间有什么区别 例如在方法之间SceneDelegate scene willConnectTo options 并在AppDele
  • Swift(UI) 错误:无法在不可变值上使用变异成员:“self”是不可变的

    基本上我想做的是 如果您按下按钮 那么条目应该获得一个新的 CEntry 如果有人能帮助我那就太好了 谢谢 struct AView View var entries CEntries var body some View ZStack V
  • SwiftUI - 将数据传递到不同的视图

    我正在开发一个有 4 个不同视图的应用程序 主视图 内容视图 an AddView an EditView 以及一个分离的DataView在一个类中 我通过一个传递所有数据可观察对象到其他意见 在主视图中我有一个项目列表 在里面AddVie
  • SwiftUI 模态视图

    从任何类或结构中模态显示 SwiftUI 视图的最佳方式是什么 我使用 UIKit 中的 UIHostingController 有没有更好的方法只使用 SwiftUI 来做到这一点 带有用于呈现 SwiftUI 视图的按钮的 Conten
  • SwiftUI 文本意外填充底部和顶部

    我需要精确控制文本所占据的区域 我创建了最基本的程序 显示意外的顶部和底部间距被添加到文本中 这些额外的填充从哪里来 如何摆脱它 main struct myApp App init var body some Scene WindowGr
  • SwiftUI:如何横向呈现全屏覆盖

    我正在制作一个应用程序 其中多个页面 视图嵌入到具有选项卡栏 菜单栏和标题的父视图中 如下所示 HeaderView MenuView TabView selection selected HomeView Page2View Page3V
  • 返回列表 (SwiftUI) 后,选定的列表行背景保持灰色(选定)。 iOS 14 + Xcode 12

    从详细信息视图返回后 所选行保持灰色 在模拟器和真实设备上都会发生 仅在 iOS 14 上 有谁知道如何删除它 使其行为与 iOS 13 上相同 不保持选中状态 这是项目中唯一的代码 没有其他导航或任何东西 let items item1
  • Swift TTS,无音频输出

    我尝试在我的应用程序 TTS 中集成 但如果单击按钮 则没有音频输出 这是按钮代码 struct VocabDetailView View var body some View HStack Button Play readOut text
  • 在一个 SwiftUI 视图中相同的 ForEach 循环两次

    当我在视图中对数组使用 ForEach 循环两次时 我在运行时收到以下警告 LazyVGridLayout the ID 84308994 9D16 48D2 975E DC40C5F9EFFF is used by multiple ch
  • 自定义“可搜索”搜索字段 SwiftUI iOS 15

    When using the new searchable modifier in SwiftUI on iOS 15 I have no way to customize the Search Bar appearance Specifi
  • 工作表关闭后 SwiftUI 导航栏项目框架未对齐

    在 SwiftUI 中关闭工作表后 导航栏按钮不可点击 以下是重现该问题的步骤 出示一张单子 将应用程序移至后台一小段时间 2 秒 恢复应用程序并向下滑动关闭工作表 现在导航栏按钮框架未对齐 点击的工作框架与按钮的可见框架不同 这在 iOS
  • 如何将图像转换为 UIImage?

    如何转换 SwiftUIImage to a UIImage let image Image systemName circle fill let UIImage image as UIImage 没有直接的方法将 Image 转换为 UI
  • SwiftUI 更新主菜单 [已解决] kludgey

    真正的问题 你如何更新mainMenu在 SwiftUI 中 它真的可以工作吗 我在 SwiftUI 中构建了一个基于 MacOS 文档的应用程序 其中包括所有内置的文件菜单命令 即关闭 保存 复制 重命名 等 在保存文档之前 我会验证结构
  • 如何观察UserDefaults的变化?

    我有一个 ObservedObject在我看来 struct HomeView View ObservedObject var station Station var body some View Text self station sta
  • 如何检测 swiftui 中是否存在键盘

    我想知道按下按钮时键盘是否存在 我该怎么做 我已经尝试过 但我没有任何运气 谢谢 使用该协议 KeyboardReadable 你可以符合任何View并从中获取键盘更新 KeyboardReadable协议 import Combine i
  • SwiftUI:动态“列表”中的“切换”在重用时会破坏其布局?

    我试图展现一种动态List行包含Toggle元素 这Toggle最初布局正确 但是当它们滚动进和滚出视图时 即单元格重用时 它们的布局会中断 最小示例代码 import SwiftUI struct SwitchList View var
  • 对成员“buildBlock()”的引用不明确

    我一直在尝试使用 Swift UI 为 iOS 13 制作一个应用程序 但我不断收到这个奇怪的错误 对成员 buildBlock 的引用不明确 无论我做什么 错误都不会消失 我尝试一次对代码段进行注释 以查看哪一部分可能导致了问题 但唯一有

随机推荐