4

I am using swipe actions in my tableview. I want to add and delete small icons on the row after a swipe action completed.

I use an asynchronous thread to do this but, it is not giving a smooth result as I wanted. My code is given below any help will be appriciated.

func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
    let groceryAction = groceryToggleAction(forRowAtIndexPath: indexPath)
    let config = UISwipeActionsConfiguration(actions: [groceryAction])
    return config
}

func tableView(_ tableView: UITableView, leadingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
    let consumeAction = consumeToggleAction(forRowAtIndexPath: indexPath)
    let config = UISwipeActionsConfiguration(actions: [consumeAction])
    return config
}

// MARK: Custom Methods
func groceryToggleAction(forRowAtIndexPath indexPath: IndexPath) -> UIContextualAction {
    let food = foods[indexPath.item]
    let action = UIContextualAction(style: .normal, title: "actionTitle") { (action, view, completionHandler) in

        let food = self.foods[indexPath.item]

        food.isAddedToGrocery = !food.isAddedToGrocery
        self.persistenceManager.saveContext()
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.4) {
            self.homeTableView.reloadRows(at: [indexPath], with: .none)
        }
        completionHandler(true)
    }
    action.image = #imageLiteral(resourceName: "shoppingCart") // İyi bir liste ikonu bul...
    action.backgroundColor = food.isAddedToGrocery ? UIColor.Palette.alizarin : UIColor.Palette.turquoise
    action.title = food.isAddedToGrocery ? "Remove" : "Add"
    return action
}

func consumeToggleAction(forRowAtIndexPath indexPath: IndexPath) -> UIContextualAction {
    let food = foods[indexPath.item]

    let action = UIContextualAction(style: .normal, title: "actionTitle") { (action, view, completionHandler) in

        food.isConsumed = !food.isConsumed
        self.persistenceManager.saveContext()
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.4) {
            self.homeTableView.reloadRows(at: [indexPath], with: .none)
        }
        completionHandler(true)

    }
    action.image = #imageLiteral(resourceName: "pacman")
    action.title = food.isConsumed ? "Remove": "Consumed!"
    action.backgroundColor = food.isConsumed ? UIColor.Palette.alizarin : UIColor.Palette.turquoise
    return action
}
pkamb
  • 33,281
  • 23
  • 160
  • 191
Ali A.
  • 101
  • 1
  • 10

3 Answers3

3

Finally I figured it out. I simply used below function from tableview delegate.

func tableView(_ tableView: UITableView, didEndEditingRowAt indexPath: IndexPath?) {
    print("did end editing")
    guard let indexPath = indexPath else {return}
    tableView.reloadRows(at: [indexPath], with: .none)
}
pkamb
  • 33,281
  • 23
  • 160
  • 191
Ali A.
  • 101
  • 1
  • 10
1

You need to integrate the UITableView delete rows, this will give that nice anim instead of the clunky reload view update.

tableView.deleteRows(at: [indexPath], with: UITableViewRowAnimation.automatic)
John Lanzivision
  • 425
  • 4
  • 12
0
DispatchQueue.main.async
{
    self.tableView.reloadData()
}

should be just enough.

In your code, you force the app to execute at a specific time. If your data is dynamic, such as remote images, they could delay the main loop more than 0.4 seconds and thus cause an even more jerky update and movement.

pkamb
  • 33,281
  • 23
  • 160
  • 191
  • Sorry. But I need to set the icon after swipe action animation is completed (After the button completely swiped off the screen). That was the reason I used 0.4 seconds delay. In the meantime my app is a complete offline app (for now...) thanks for the answer though... – Ali A. Jan 17 '19 at 18:49
  • Could you place the "DispatchQueue.main.async" function inside the completion handler, instead? – Johannes Schidlowski Jan 17 '19 at 18:59
  • I prepared below given function and put it inside `complationHandler( self. updateRow())`. But, the behavior is still the same. The row updates itself immediately after the swipe button is pressed. `func updateRow() -> Bool { DispatchQueue.main.async { self.homeTableView.reloadData() } return true }` – Ali A. Jan 18 '19 at 06:58