8

After looking into a myriad of StackOverflow posts, nothing really answers how to delete a UITableViewCell with swipe-to-dismiss while fading and without the red delete button.

My Tableviewcell looks like a card, so the red frame of the delete button breaks the sense of continuity and elevation of these cells with card shapes.

Here is the code I am currently using to delete, which does not fade despite the .fade on the UITableViewRowAnimation.

func tableView(_ tableView: UITableView, shouldIndentWhileEditingRowAt indexPath: IndexPath) -> Bool {
    return false
}

func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCellEditingStyle {
    return .none
}

func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
    if editingStyle == .delete {
        self.pastOrders.remove(at: indexPath.row)
        tableView.deleteRows(at: [indexPath], with: .fade)
    }
}

Here's a screenshot of the behavior I am trying to achieve:

enter image description here

rgoncalv
  • 5,825
  • 6
  • 34
  • 61

6 Answers6

2

Output 3

 //TO CHANGE "DELETE" TITLE COLOR

func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {

        let toDelete = UITableViewRowAction(style: .normal, title: "") { (action, indexPath) in
            print("\n\n Delete item at indexPathDelete item at indexPath")
        }


        let deleteTextImg = swipeCellButtons(labelText: "Delete", textColor: UIColor.darkGray, alphaVal: 1.0)

        toDelete.backgroundColor = UIColor(patternImage: deleteTextImg)
        return [toDelete]
  }


func swipeCellButtons(labelText : String, textColor: UIColor, alphaVal: CGFloat) -> UIImage
 {
     let commonWid : CGFloat = 40
     let commonHei : CGFloat = 70 // ROW HEIGHT
     let label = UILabel(frame: CGRect(x: 0, y: 0, width: commonWid, height: commonHei))
     label.text = labelText
     label.textAlignment = .center
     label.font = UIFont.systemFont(ofSize: 11)
     label.textColor = textColor.withAlphaComponent(alphaVal)

     UIGraphicsBeginImageContextWithOptions(CGSize(width: self.view.frame.width, height: commonHei), false, UIScreen.main.scale)
     let context = UIGraphicsGetCurrentContext()

     context!.setFillColor(UIColor.clear.cgColor) // YOU CAN GIVE YOUR BGCOLOR FOR DELETE BUTTON 
     context!.fill(CGRect(x: 0, y: 0, width: (self.view.frame.width) / 3, height: commonHei))
     label.layer.render(in: context!)

     //If you want to add image instead of text, uncomment below lines.
     //Then, comment this "label.layer.render(in: context!)" line

     //var img: UIImage = UIImage(named: "deleteIcon")!
     //img.draw(in: CGRect(x: 0, y: 0, width: 30, height: 30))

     let newImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()!
     UIGraphicsEndImageContext()
     return newImage
 }

Output 2:

// INSIDE CELL FOR ROW AT INDEXPATH

// COMMENT THIS LINE
//cell.addGestureRecognizer(swipeGesture)


// CELL FADE WILL NOT WORK HERE
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {

        let toDelete = UITableViewRowAction(style: .normal, title: "   ") { (action, indexPath) in
            print("\n\n Delete item at indexPathDelete item at indexPath")
        }


        toDelete.backgroundColor = .white

        return [toDelete]
  }

Output 1:

// GLOBAL DECLARATION
var gotCell : DefaultTableViewCell?
var alphaValue : CGFloat = 1.0
var deletingRowIndPath = IndexPath()     


 // INSIDE CELL FOR ROW AT INDEXPATH

 //let cell = tableView.dequeueReusableCell(withIdentifier: "default", for: indexPath) as! DefaultTableViewCell
 let cell = DefaultTableViewCell() // Add this line and comment above line. The issue is `dequeuingreusingcell`. In this method, it will stop dequeuing. But, we have to customise `UITableViewCell` in coding. 
 let swipeGesture = UIPanGestureRecognizer(target: self, action: #selector(handleSwipe))
 swipeGesture.delegate = self
 cell.addGestureRecognizer(swipeGesture)


 func handleSwipe(panGesture: UIPanGestureRecognizer) {

    if panGesture.state == UIGestureRecognizerState.began {

        let cellPosition = panGesture.view?.convert(CGPoint.zero, to: defTblVw)
        let indPath = defTblVw.indexPathForRow(at: cellPosition!)

        deletingRowIndPath = indPath!

        gotCell = defTblVw.cellForRow(at: indPath!) as! DefaultTableViewCell

    }

    if panGesture.state == UIGestureRecognizerState.changed
    {
        let isLeftMoving = panGesture.isLeft(theViewYouArePassing: (gotCell)!)

        if isLeftMoving == true
        {
            self.gotCell?.alpha = self.alphaValue

            self.gotCell?.frame.origin.x = (self.gotCell?.frame.origin.x)! - 2.5
            self.view.layoutIfNeeded()

            self.alphaValue = self.alphaValue - 0.005

        }
        else // ADD THIS ELSE CASE
        {
            self.alphaValue = 1.0
            self.gotCell?.alpha = 1.0
            UIView.animate(withDuration: 0.8, animations: {

                self.gotCell?.frame.origin.x = 0
                self.view.layoutIfNeeded()
            }) { (value) in
            }
        }
    }

    if panGesture.state == UIGestureRecognizerState.ended
    {
        self.alphaValue = 1.0

        if (self.gotCell?.frame.origin.x)! < CGFloat(-(defTblVw.frame.size.width - 90))
        {

            myArr.remove(at: (deletingRowIndPath.row))

            defTblVw.beginUpdates()
            defTblVw.deleteRows(at: [deletingRowIndPath], with: UITableViewRowAnimation.fade)
            defTblVw.endUpdates()
        }
        else
        {
            UIView.animate(withDuration: 0.8, animations: {

                self.gotCell?.alpha = 1.0
                self.gotCell?.frame.origin.x = 0
                self.view.layoutIfNeeded()
            }) { (value) in
            }
        }

    }

}


func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {

    return true
}


extension UIPanGestureRecognizer {

 func isLeft(theViewYouArePassing: UIView) -> Bool {
    let velocityVal : CGPoint = velocity(in: theViewYouArePassing)
    if velocityVal.x >= 0 {
          return false
    }
    else
    {

        print("Gesture went other")
        return true
    }
 }
}

=============================

McDonal_11
  • 3,935
  • 6
  • 24
  • 55
  • +1 for the simple approach. I guess cell won't follow finger if implemented this way? Not sure how intuitive is the UX? – zc246 Jan 30 '18 at 09:02
  • @McDonal_11, I really like what you did. It seems you're really close (the edit), but there are still some problems in this approach as (user cannot pan it back without canceling the touch) and it's weird but the velocity that the row moves is different based on where the touch is (edge of the cell of center of it) – rgoncalv Jan 30 '18 at 22:27
  • I had figured out this method which work on iOS < 11, so great as well :). A problem that both of the built-in methods share is the delete title being white and thus, a white background that when the user clicks (indented mode) , deletes the row even though being "invisible". Changing the button title color would solve it but the only way around this is to change all app button's title color simultaneously. – rgoncalv Jan 31 '18 at 14:49
  • "Changing the button title color would solve it but the only way around this is to change all app button's title color simultaneously" **I can't understood this.** – McDonal_11 Feb 01 '18 at 04:41
  • The only way it's possible to change the cell's delete button title color is by calling `UIButton.appearance().setTitleColor(UIColor.redColor(), forState: UIControlState.Normal)`, which changes the appearance of all `UIButton`s in the project – rgoncalv Feb 01 '18 at 06:12
  • UIGraphicsBeginImageContextWithOptions . with the help of this, u can change "Delete" button title color . – McDonal_11 Feb 01 '18 at 06:21
  • If user swipes cell leftwards, at that time, u having white background with shadow and "Delete" button with different color or "no delete" button ?? – McDonal_11 Feb 01 '18 at 06:23
  • It would be awesome to not have a delete button, but I can't think of a way to not have the cell indented if the user swipes and cancels halfway across. Therefore, Since by using the standard API (`editActionsForRow:` for instance) the cells has indentation, it's weird to be able to click in a white indented space and the cell get deleted. Thus, indicating there's a delete button right there with a delete title with some color different from white is necessary – rgoncalv Feb 02 '18 at 01:28
  • Problem with OUTPUT3 is that the cell cannot be swiped until disappearing anymore but only if clicked on button (which is solved by delete having a distinct color or image). I am using a resizable cell (automatic height), so this presents another problem to the equation (In some cells the image for instance gets patterned twice in a single cell since there's space left, e.g cell is greater than the standard) – rgoncalv Feb 03 '18 at 17:58
1

I guess SwipeCellKit pod is an option as well to do swiping without delete button, so please check out this link: https://github.com/SwipeCellKit/SwipeCellKit.

There is all documentation how you can customize it and if you can see the Destructive gif on the link, it is what you wanted, however you have to make it custom so there is no other buttons nor the delete button as well.

I hope it helped you somehow.

Latenec
  • 408
  • 6
  • 21
0

You can use this library with .exit mode

and In your cellForRow

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! SwipyCell //User You cell identifier and class of cell here

    let checkView = viewWithImageName("check") //Use some white dummy image


    cell.addSwipeTrigger(forState: .state(0, .left), withMode: .exit, swipeView: checkView, swipeColor: tableView.backgroundView?.backgroundColor, completion: { cell, trigger, state, mode in
        print("Did swipe \"Checkmark\" cell")
    })


    return cell
}

Hope this will help you

Ganesh Manickam
  • 2,113
  • 3
  • 20
  • 28
0

Try this code.

func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {

        let toDelete = UITableViewRowAction(style: .normal, title: "   ") { (action, indexPath) in
            self.rows.remove(at: indexPath.row)
            tableView.deleteRows(at: [indexPath], with: .fade)
        }

        toDelete.backgroundColor = .white

        return [toDelete]
    }

Hope it would help you.

Inder Jagdeo
  • 229
  • 2
  • 9
0

You can animate the content view and on completion of animation you can delete the cell

Vishnu
  • 56
  • 1
  • 12
0

You can add a swipe gesture on the content of your custom cell, when the swipe animation is over you call a delegate method to the ViewController in which it will update the data array delete the tableView row and reload the tableView.

J. Koush
  • 1,028
  • 1
  • 11
  • 17