Updated with working code.
I've implemented a List in my app with Edit mode, so I can move the rows by dragging a row handle. That works fine, but doesn't look too good, since the move icon is placed under the content of the row (see screen dump). And that is because Edit mode makes room for a delete button.
Is there a way to hide elements in the row when you're in Edit mode?
The code for the View is:
import SwiftUI
import Combine
import DateHelper
struct EggList: View {
@EnvironmentObject var egg : Egg
@State private var eggs = Egg.all()
@State private var editMode: EditMode = .inactive
var body: some View {
NavigationView {
List {
Image("Pantanal")
.resizable()
.frame(height: 250)
ForEach(eggs) { eggItem in
NavigationLink(destination: EggDayList(eggItem: eggItem)) {
CellRow(eggItem: eggItem)
.environment(\.editMode, self.$editMode)
}
}
.onDelete(perform: delete)
.onMove(perform: move)
}
.navigationBarTitle(Text("Eggs"), displayMode: .inline)
.navigationBarItems(leading: EditButton(), trailing: NavigationLink(destination: Settings()){
Text("Add Egg")})
.environment(\.editMode, self.$editMode)
}
}
func delete(at offsets: IndexSet) {
eggs.remove(atOffsets: offsets)
}
func move(from source: IndexSet, to destination: Int) {
eggs.move(fromOffsets: source, toOffset: destination)
}
}
struct CellRow: View {
let eggItem: Egg
@Environment(\.editMode) private var editMode
var body: some View {
HStack(spacing: 8) {
Image(eggItem.species)
.resizable()
.frame(width: 48, height: 48)
.clipShape(Circle())
VStack(alignment: .leading, spacing: 0) {
Text("\(eggItem.species)")
.font(.footnote)
.lineLimit(1)
.padding(.top, -4)
Text("id-"+String(eggItem.eggNumber))
.font(.footnote)
.lineLimit(1)
.padding(0)
Text("\(eggItem.layDate.string(with: "dd-MM-yy"))")
.font(.footnote)
.lineLimit(1)
.padding(.bottom, -7)
}.frame(width: 90, alignment: .leading)
VStack(spacing: 2) {
Text("days")
.font(.footnote)
.padding(.top, 12)
Image(systemName: "\(eggItem.diffToday)"+".circle")
.resizable()
.frame(width: 40, height: 30)
.padding(.bottom, 12)
.foregroundColor(.red)
}.frame(width: 50, alignment: .leading)
VStack(spacing: 0) {
Text("prediction")
.font(.footnote)
.padding(.top, 14)
Text(formatVar1(getal: eggItem.calcWeights[eggItem.daysToPip-1].prediction)+"%")
.font(.title)
.padding(.bottom, 12)
}.frame(width: 80, alignment: .leading)
if !(self.editMode?.wrappedValue.isEditing ?? false) {
VStack(alignment: .leading, spacing: 0) {
Text("INC")
.font(.footnote)
.lineLimit(1)
.padding(.top, -4)
Text("37.3")
.font(.footnote)
.lineLimit(1)
.padding(0)
Text("30%")
.font(.footnote)
.lineLimit(1)
.padding(.bottom, -7)
}
.frame(width: 30, alignment: .leading)
}
Spacer()
VStack(alignment: .trailing, spacing: 0) {
Image(systemName: "info.circle")
.resizable()
.frame(width: 22, height: 22)
.foregroundColor(.accentColor)
.onTapGesture(count: 1) {
print("action")
}
}
}
.listRowInsets(.init(top: 0, leading: 0, bottom: 0, trailing: 0))
.frame(height: 46, alignment: .leading)
.padding(0)
}
}
Your problem is, that the editMode
variable does not change when you press the EditButton. No matter in what state, in your CellRow the editMode
variable always returns .inactive
. I don't know why, it could be a bug.
I had the same problem, but I found this question here: SwiftUI - How do I make edit rows in a list?, which uses a workaround by passing the editMode
environment value into a private @State
variable, which seems to work perfect.
So here is what you need to do:
@State private var editMode: EditMode = .inactive
to your EggList view.
This creates a state variable that from now on holds the editing mode.
.environment(\.editMode, self.$editMode)
somewhere after the .navigationBarItems(...)
.
This sets the environment variable
editMode
inEggList
to a binding of the state variable above.
.environment(\.editMode, self.$editMode)
directly after the CellRow(...)
initializer.
This inserts the state variable
editMode
into the environment ofCellRow
, where it can be accessed via@Environment(\.editMode)
.
Now you can just wrap one of your elements in an if-statement to hide it when in editing mode:
if !self.editMode?.wrappedValue.isEditing ?? true {
VStack(alignment: .leading, spacing: 0) {
Text("INC")
.font(.footnote)
.lineLimit(1)
.padding(.top, -4)
Text("37.3")
.font(.footnote)
.lineLimit(1)
.padding(0)
Text("30%")
.font(.footnote)
.lineLimit(1)
.padding(.bottom, -7)
}
.frame(width: 30, alignment: .leading)
}
or, if you prefer, continue using the isHidden
extension from LuLuGaGa:
.isHidden(self.editMode?.wrappedValue.isEditing ?? false)