How to delete UITableViewCell with swipe-to-dismiss with fade effect and no red delete button?
Asked Answered
G

6

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

Gertie answered 27/1, 2018 at 14:26 Comment(6)
UISwipeRecognizer in UITableViewCell ? then, add animation while deleting ?Adenoma
Can u post screenshot?Adenoma
@McDonal_11, see my edit pleaseGertie
You want this type of fade animation, but without delete button, simply white background. Am I right ?Adenoma
I have edited my answer once again. Kindly check it @GertieAdenoma
Issue is Dequeuing. So, Velocity is automatically increased. I have edited again. U may check.Adenoma
A
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
    }
 }
}

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

Adenoma answered 29/1, 2018 at 16:11 Comment(9)
+1 for the simple approach. I guess cell won't follow finger if implemented this way? Not sure how intuitive is the UX?Brinson
@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)Gertie
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.Gertie
"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.Adenoma
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 UIButtons in the projectGertie
UIGraphicsBeginImageContextWithOptions . with the help of this, u can change "Delete" button title color .Adenoma
If user swipes cell leftwards, at that time, u having white background with shadow and "Delete" button with different color or "no delete" button ??Adenoma
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 necessaryGertie
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)Gertie
S
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.

Saskatchewan answered 4/2, 2018 at 16:41 Comment(0)
B
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

Burnard answered 1/2, 2018 at 5:4 Comment(0)
E
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.

Exclosure answered 1/2, 2018 at 6:2 Comment(0)
O
0

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

Oreilly answered 1/2, 2018 at 19:26 Comment(0)
B
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.

Bega answered 3/2, 2018 at 9:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.