Flutter iOS flutter_swipe_action_cell not updating UI after deleting cell

Issue

I have a ListView containing 5 elements in the following order:

  • Section Header
  • Valid Item 0
  • Valid Item 1
  • Section Header
  • Invalid Item 0

When I swipe to delete Valid Item 0, the ListView length becomes 4 instead of 5 (as expected), the UI appears in the order below, with only 3 items. I have also determined that each element in the ListView.builder, is being returned correctly (in the order above, except for Valid Item 0, as expected). Each Widget is being build as expected.

  • Section Header
  • Section Header
  • Invalid Item 0

The UI appears correctly until I call setState(() {}). Once it is called, Valid Item 1 is removed from the UI, but not the data source. If I switch the current display to a different Scaffold (as shown in the video below), then switch back, the UI shows correctly again. Strange.

Using the flutter_swipe_action_cell package, I have added a delete button that appears when the cell is swiped to the left.
I followed this example:

SwipeAction(
  title: "delete",
  onTap: (CompletionHandler handler) async {           
    /// await handler(true) : will delete this row
    /// And after delete animation, setState will called to 
    /// sync your data source with your UI

    await handler(true);
    list.removeAt(index);
    setState(() {});
  },
  color: Colors.red
)

With this code:

SwipeAction(
  icon: Container(
    margin: const EdgeInsets.only(bottom: 4),
    child: const Icon(
      Icons.delete,
      size: 30,
    )
  ),
  title: "Delete",
  performsFirstActionWithFullSwipe: true,
  onTap: (CompletionHandler handler) async {
    print("Delete Profile (valid @ ${index - 1})");
    await handler(true);
    (data["valid"] as List).removeAt(index - 1);
    setState(() {});
  },
  color: Colors.red
)

This is a recording of my issue:

Screen Recording

Solution

I ended up figuring it out myself after several hours of trial and error.
The key component here is literally key. I didn’t realize the purpose of the key initially. It seems to be used to coordinate which cell is being deleted on the UI with its corresponding data. The key for each SwipeActionCell should reference the exact same data child which will be deleted.

SwipeActionCell(
  key: ObjectKey(data["valid"]![privateIndex]),
  ...
)

where privateIndex is the index for the list item in that section, ignoring any section headers and previous sections. Eg:

1. Section Header    listIndex: 0    privateIndex: N/A
2. Valid Item 0      listIndex: 1    privateIndex: 0
3. Valid Item 1      listIndex: 2    privateIndex: 1
4. Section Header    listIndex: 3    privateIndex: N/A
5. Invalid Item 0    listIndex: 4    privateIndex: 0

and where data is:

Map<String,List<dynamic>> data = {
  "valid": [
    {"title":"Valid Item 0"},
    {"title":"Valid Item 1"}
  ],
  "invalid": [
    {"title":"Invalid Item 0"}
  ]
}

Answered By – SwiftCODA

Answer Checked By – Mildred Charles (FlutterFixes Admin)

Leave a Reply

Your email address will not be published. Required fields are marked *