具有多个 EditButton 的 SwiftUI 表单
SwiftUI Form with Multiple EditButtons
尝试让 Form
包含多个部分,每个 Section
都有自己的 EditButton
。
如何在不触发 Form
中的所有部分的情况下触发 Section
进入“编辑模式”,如所附 gif 所示。
如何跟踪某个Section
中的EditButton
是否被触发,从而使Section
中出现Button
。
我使用了这两个来源的代码:
developer.apple.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()
}
}
没有为每个部分设置不同编辑模式的内置工具。
但是您可以明确地使用它来设置编辑模式和disable/enable每行的删除和移动操作。
这是可能的解决方案演示。
为此,您需要先创建自己的具有绑定布尔值的 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)
}
}
尝试让 Form
包含多个部分,每个 Section
都有自己的 EditButton
。
如何在不触发
Form
中的所有部分的情况下触发Section
进入“编辑模式”,如所附 gif 所示。如何跟踪某个
Section
中的EditButton
是否被触发,从而使Section
中出现Button
。
我使用了这两个来源的代码:
developer.apple.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()
}
}
没有为每个部分设置不同编辑模式的内置工具。
但是您可以明确地使用它来设置编辑模式和disable/enable每行的删除和移动操作。
这是可能的解决方案演示。
为此,您需要先创建自己的具有绑定布尔值的 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)
}
}