3

I have two UIContextualActions which should delete rows from the table after completion. I faced the following intermittent issue: If I apply this actions very fast one by one, then the first action works fine, but when I call UIContextualAction's menu for the second time it overlaps the cell. In the third time, it is not possible to call UIContextualAction's menu until tableView is scrolled. Here the short video.

Please find below the piece of code

    //MARK: Swipe actions
override func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
    let deleteAction = self.contextualDeleteAction(forRowAtIndexPath: indexPath)
    let markAsReadAction = self.contextualMarkAsReadAction(forRowAtIndexPath: indexPath)
    let markAsUnreadAction = self.contextualMarkAsUnreadAction(forRowAtIndexPath: indexPath)
    let swipeConfig = UISwipeActionsConfiguration(actions: [
        isArchiveModeEnabled ? markAsUnreadAction : markAsReadAction,
        deleteAction
        ])

    swipeConfig.performsFirstActionWithFullSwipe = false

    return swipeConfig
}

func contextualMarkAsUnreadAction(forRowAtIndexPath indexPath: IndexPath) -> UIContextualAction {
    let action = UIContextualAction(style: .normal, title: "") { _, _, completion in
        let index = indexPath.row

        if let article = self.getSelectedArticleByIndex(index) {
            self.articlesManager.restore(article: article)
            self.refreshDataSource()
            self.tableView.deleteRows(at: [indexPath], with: .automatic)
            self.tableView.isEditing = false //seems like it helps to fix visual bug when the action is left on blank space
            completion(true)
        }
    }

    action.backgroundColor =  UIColor(patternImage: swipeActinImages.markAsUnread)

    return action
}

refreshDataSource function do the following:

 private func refreshDataSource() {
    articles = isArchiveModeEnabled ? dataController.getArchivedArticles() : dataController.getUnreadArticles()
}    

private func reloadTableData() {
    if dataController.getActiveUser() != nil {
        refreshDataSource()
        introView?.isHidden = articles.count != 0 || isArchiveModeEnabled
        tableView.isScrollEnabled = (introView?.isHidden)!

        DispatchQueue.main.async {
            self.tableView.reloadData()
        }
    }
}

Appreciate any help

UPDATE

So I solved it. I've replaced UIContextualAction(style: .normal, title: "") to UIContextualAction(style: .destructive, title: "") and don't update datasource manualy anymore. Completion(true) do all needed manipulation with cell and table automaticaly.

The final code is

    func contextualMarkAsUnreadAction(forRowAtIndexPath indexPath: IndexPath) -> UIContextualAction {
    let action = UIContextualAction(style: .destructive, title: "") { _, _, completion in
        let index = indexPath.row

        if let article = self.getSelectedArticleByIndex(index) {
            self.articlesManager.restore(article: article)
            //self.refreshDataSource()
            completion(true)
        } else {
            completion(false)
        }
    }

    action.backgroundColor =  UIColor(patternImage: swipeActinImages.markAsUnread)

    return action
}
Alexey Gorbel
  • 220
  • 3
  • 11

0 Answers0