skip to Main Content

I have an already completed screen in which I have added a listing using UITableView which is inside a UIViewController. Now, I have to add swipe to delete functionality. I see several swipe to delete implementations but all of them assume that UITableViewController is used. Is there a way I can get same functionality in my UITableView which is inside a UIViewController?

I have tried but I can’t achive that goal.

2

Answers


  1. You can do it inside UIViewController as well. You have to implement below 2 functions inside your UIViewController:

    func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
        return true
    }
    
    func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
        // Implement delete functionality. 
        tableView.reloadData()
    }
    
    Login or Signup to reply.
  2. I had a problem where my cells were not adjacent to the screen edges and there was some spacing so the default implementation would not look good.

    So if you want to add swipe to delete functionality you can very easily add your own custom swipe to delete functionality by:

    1. Adding swipe gesture to your table cell and set the correct direction.
    2. Modify your table cell such that it has a delete button hidden at the far right behind the content.
    3. Upon swipe, move your cells content such that the delete button becomes visible. A simple animation will add the effect of button revealing from the right side. Also fire a notification ‘DidSwipeCell’
    4. Now capture the delete button press event, you have to pass this information to the parent viewcontroller so that data can actually be deleted. This can be very easily achieved by a Delegate protocol.
    5. Remove the item from data and cell from the table.
    6. Add a notification observer in the cell to listen to ‘DidSwipeCell’ notification so that if any other cell is swiped, or if user cancels the swipe by tapping on the cell, swipe back the current cell.

    Here is the my cell class with basic implementation:

    // Delegate to let VC know about delete action
    protocol NotificationTableCellDelegate: class {
        func didDeleteTapped(id: String)
    }
    
    class NotificationTableCell: UITableViewCell {
        @IBOutlet weak var contentContainer: UIView!
        @IBOutlet weak var checkButton: UIButton!
        @IBOutlet weak var titleLabel: UILabel!
        @IBOutlet weak var timeLabel: UILabel!
        @IBOutlet weak var typeImage: UIImageView!
    
    
    @IBOutlet weak var main_container_trailing: NSLayoutConstraint!
    // id required to identify the cell/item, can be the database id of object or simply
    // index
    private var currentId = ""
    // to keep track if cell is swiped or not
    var swiped = false
    // distance to slide to reveal delete button
    var slideOffset = 60.0
    // tap Gesture used to swipe-back to normal position
    weak var tapGesture: UITapGestureRecognizer?
    
    weak var delegate: NotificationTableCellDelegate?
    
    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code
        
        // Add swipe left gesture
        let swipeGesture = UISwipeGestureRecognizer(target: self, action: #selector(didSwipeCell))
        swipeGesture.direction = .left
        self.contentContainer.addGestureRecognizer(swipeGesture)
        
        // Add notification listener for any swipe performed in the table
        NotificationCenter.observeNotification(name: AppData.internalNotifications.NotificationTableCellDidSwipe, observer: self, selector: #selector(handleSwipeNotification))
    }
    
    override func prepareForReuse() {
        // on reuse, slide back
        self.slideBack()
    }
    
    // on delete, remove observer
    override func delete(_ sender: Any?) {
        NotificationCenter.removeObserver(observer: self)
    }
    
    @IBAction func deleteButtonTapped(sender: UIButton) {
        // let delegate know when cell is deleted, pass id 
        self.delegate?.didDeleteTapped(id: currentId)
    }
    
    @objc func didSwipeCell(_ sender: UISwipeGestureRecognizer) {
        // upon swipe, slide main container to reveal delete button
        self.slideMainContainer()
        // Add tapgesture on the sliding view so that if user
        // tap the cell, delete gesture is cancelled
        self.addTapGestureToContentContainer()
    }
    
    @objc func handleSwipeNotification(notification: Notification) {
        guard let currentId = notification.userInfo?["currentId"] as? String else {
            return
        }
        
        // if notification is from this very cell, return
        if !currentId.isEmpty, currentId == self.currentId {
            return
        }
        
        // if some other cell is swiped, swipe this cell back
        self.slideBack()
    }
    
    func slideMainContainer() {
        let constant = self.main_container_trailing.constant
        UIView.animate(withDuration: 0.2) {
            self.main_container_trailing.constant = constant == 0 ? self.slideOffset : 0.0
            self.contentContainer.superview?.setNeedsLayout()
            self.contentContainer.superview?.layoutIfNeeded()
            
            // Post swipe notification
            NotificationCenter.post(name: AppData.internalNotifications.NotificationTableCellDidSwipe, userInfo: ["currentId" : self.currentId])
        }
    }
    
    func addTapGestureToContentContainer() {
        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(slideBack(animated:)))
        tapGesture.numberOfTapsRequired = 1
        
        self.contentContainer.addGestureRecognizer(tapGesture)
        self.tapGesture = tapGesture
    }
    
    func removeTapGestureFromContentContainer() {
        guard let tapGesture = self.tapGesture else {
            return
        }
        self.contentContainer.removeGestureRecognizer(tapGesture)
    }
    
    @objc func slideBack(animated: Bool = true) {
        UIView.animate(withDuration: 0.2) {
            self.main_container_trailing.constant = 0.0
            self.contentContainer.superview?.setNeedsLayout()
            self.contentContainer.superview?.layoutIfNeeded()
        }
    
        self.removeTapGestureFromContentContainer()
      }
    }
    

    custom swipe

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search