I have a list to show some records. A weird issue will happen as follow steps:
--tap "insert" button for some times(eg. 3 times)
--swipe a record from right to left to delete it
--tap "edit" button to switch to edit mode
--tap "insert" button to insert a new record
The first 2 records both have a "option button"(a small hollow circle). BUT the last inserted record has no "option button". The list seems like to reuse the view of the deleted record in "non-edit" mode. All of the 3 records can be selected by click. I wonder how to make the inserted record to also have a "option button".
struct ListEditModeSubviewUpdateTest: View {
@State private var data = [Int]()
@State private var editMode = EditMode.inactive
@State private var selects = Set<Int>()
@State private var base = 0
var body: some View{
VStack{
Button {
if editMode.isEditing{
editMode = .inactive
}else{
editMode = .active
}
} label: {
Text(editMode.isEditing ? "Done" : "Edit")
}
Button {
base += 1
data.append(base)
} label: {
Text("Insert")
}
List(selection: $selects){
ForEach(data, id:\.self){item in
Text(String(item))
}
.onDelete{
data.remove(atOffsets: $0)
}
}
}
.environment(\.editMode, $editMode)
}
}
Here is possible workaround. Tested with Xcode 13.4 / iOS 15.5
// explicit state to force refresh List that
// will drop cached cells
@State private var forceRefresh = false
var body: some View{
VStack{
Button {
if editMode.isEditing{
editMode = .inactive
}else{
editMode = .active
}
// [!!!] cannot use `editMode` directly because it is also
// changed on swipe to delete
forceRefresh.toggle() // << here !!
} label: {
Text(editMode.isEditing ? "Done" : "Edit")
}
Button {
base += 1
data.append(base)
} label: {
Text("Insert")
}
List(selection: $selects){
ForEach(data, id:\.self){item in
Text(String(item)).id(item)
}
.onDelete{
data.remove(atOffsets: $0)
}
}
.id(forceRefresh) // << here !!
}
.environment(\.editMode, $editMode)
}