Swipe-Able Table View Cell in iOS 9

Swipe-able Table View Cell in iOS 9

Try this, updated for Swift 3 (Developer Docs)

override func tableView(_ tableView: UITableView, editActionsForRowAt: IndexPath) -> [UITableViewRowAction]? {
let more = UITableViewRowAction(style: .normal, title: "More") { action, index in
print("more button tapped")
}
more.backgroundColor = .lightGray

let favorite = UITableViewRowAction(style: .normal, title: "Favorite") { action, index in
print("favorite button tapped")
}
favorite.backgroundColor = .orange

let share = UITableViewRowAction(style: .normal, title: "Share") { action, index in
print("share button tapped")
}
share.backgroundColor = .blue

return [share, favorite, more]
}

Also implement this: (You can make it conditional, but here everything is editable)

override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return true
}

Swiping right on a UITableViewCell

No, there Is no such native API as of now.

How to add a Swipe Left gesture to a TableView and return the cell location when swiped in Swift 3

I've done some research and created a bare-bones example of how to this - create a table cell that can be swiped AND tapped. I'm using it in a music player - tap a cell and play the song, swipe the same cell and segue to a different view.

I've built my solution based on these two existing samples:
https://www.raywenderlich.com/77974/making-a-gesture-driven-to-do-list-app-like-clear-in-swift-part-1

https://gabrielghe.github.io/swift/2016/03/20/swipable-uitableviewcell

I don't have a repository to share so all the code is here.

I'm using Xcode 8.2.1 and Swift 3

STEP 1:

  • Create a New, Single-View Swift project, and open the Storyboard.
  • Drag a TableView onto the existing ViewController and drag it to fit the view.

STEP 2:

  • Add new Swift File to the Project and name it "TableViewCellSliding.swift".
  • Copy/paste the code below into the new file.

    //
    // TableViewCellSliding.swift
    //

    import UIKit

    protocol SlidingCellDelegate {
    // tell the TableView that a swipe happened
    func hasPerformedSwipe(touch: CGPoint)
    func hasPerformedTap(touch: CGPoint)
    }

    class SlidingTableViewCell: UITableViewCell {
    var delegate: SlidingCellDelegate?
    var originalCenter = CGPoint()
    var isSwipeSuccessful = false
    var touch = CGPoint()

    required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
    }

    override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
    super.init(style: style, reuseIdentifier: reuseIdentifier)

    // add a PAN gesture
    let pRecognizer = UIPanGestureRecognizer(target: self, action: #selector(SlidingTableViewCell.handlePan(_:)))
    pRecognizer.delegate = self
    addGestureRecognizer(pRecognizer)

    // add a TAP gesture
    // note that adding the PAN gesture to a cell disables the built-in tap responder (didSelectRowAtIndexPath)
    // so we can add in our own here if we want both swipe and tap actions
    let tRecognizer = UITapGestureRecognizer(target: self, action: #selector(SlidingTableViewCell.handleTap(_:)))
    tRecognizer.delegate = self
    addGestureRecognizer(tRecognizer)
    }

    override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
    if let panGestureRecognizer = gestureRecognizer as? UIPanGestureRecognizer {
    let translation = panGestureRecognizer.translation(in: superview!)
    //look for right-swipe
    if (fabs(translation.x) > fabs(translation.y)) && (translation.x > 0){

    // look for left-swipe
    //if (fabs(translation.x) > fabs(translation.y)) && (translation.x < 0){
    //print("gesture 1")
    touch = panGestureRecognizer.location(in: superview)
    return true
    }
    //not left or right - must be up or down
    return false
    }else if gestureRecognizer is UITapGestureRecognizer {
    touch = gestureRecognizer.location(in: superview)
    return true
    }
    return false
    }

    func handleTap(_ recognizer: UITapGestureRecognizer){
    // call function to get indexPath since didSelectRowAtIndexPath will be disabled
    delegate?.hasPerformedTap(touch: touch)
    }

    func handlePan(_ recognizer: UIPanGestureRecognizer) {
    if recognizer.state == .began {
    originalCenter = center
    }

    if recognizer.state == .changed {
    checkIfSwiped(recongizer: recognizer)
    }

    if recognizer.state == .ended {
    let originalFrame = CGRect(x: 0, y: frame.origin.y, width: bounds.size.width, height: bounds.size.height)
    if isSwipeSuccessful{
    delegate?.hasPerformedSwipe(touch: touch)

    //after 'short' swipe animate back to origin quickly
    moveViewBackIntoPlaceSlowly(originalFrame: originalFrame)
    } else {
    //after successful swipe animate back to origin slowly
    moveViewBackIntoPlace(originalFrame: originalFrame)
    }
    }
    }

    func checkIfSwiped(recongizer: UIPanGestureRecognizer) {
    let translation = recongizer.translation(in: self)
    center = CGPoint(x: originalCenter.x + translation.x, y: originalCenter.y)

    //this allows only swipe-right
    isSwipeSuccessful = frame.origin.x > frame.size.width / 2.0 //pan is 1/2 width of the cell

    //this allows only swipe-left
    //isSwipeSuccessful = frame.origin.x < -frame.size.width / 3.0 //pan is 1/3 width of the cell
    }

    func moveViewBackIntoPlace(originalFrame: CGRect) {
    UIView.animate(withDuration: 0.2, animations: {self.frame = originalFrame})
    }
    func moveViewBackIntoPlaceSlowly(originalFrame: CGRect) {
    UIView.animate(withDuration: 1.5, animations: {self.frame = originalFrame})
    }

    }

STEP 3:

  • Copy/paste the code below into the existing file "ViewController.swift"

    //
    // ViewController.swift
    //

    import UIKit

    class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, SlidingCellDelegate {

    @IBOutlet weak var tableView: UITableView!

    override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.

    tableView.dataSource = self
    tableView.delegate = self
    tableView.register(SlidingTableViewCell.self, forCellReuseIdentifier: "cell")
    tableView.rowHeight = 50;
    }

    func hasPerformedSwipe(touch: CGPoint) {
    if let indexPath = tableView.indexPathForRow(at: touch) {
    // Access the image or the cell at this index path
    print("got a swipe row:\(indexPath.row)")
    }
    }

    func hasPerformedTap(touch: CGPoint){
    if let indexPath = tableView.indexPathForRow(at: touch) {
    // Access the image or the cell at this index path
    print("got a tap row:\(indexPath.row)")
    }
    }

    override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
    }

    func numberOfSectionsInTableView(tableView: UITableView) -> Int {
    return 1
    }
    func tableView(_ tableView: UITableView,numberOfRowsInSection section: Int)-> Int {
    return 100
    }
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell=tableView.dequeueReusableCell(withIdentifier: "cell",for: indexPath) as! SlidingTableViewCell
    // Configure cell
    cell.selectionStyle = .none
    cell.textLabel?.text = "hello \(indexPath.row)"
    cell.delegate = self
    return cell
    }
    func tableView(sender: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
    // do stuff with indexPath.row and indexPath.section
    //never make it here because we added a tap gesture but this will
    print("selected cell")
    }
    }

STEP 4:

Connect it all in the Storyboard.

  • Open the Storyboard view and select the TableView. Go to the Connections Inspector (upper-right corner arrow in a circle) and drag from New Referencing Outlet to the TableView and select "tableView" from the popup menu.

  • With the TableView still selected, drag from Outlets > dataSource to the TableView in the Storyboard. Repeat starting with Outlets > delegate.

STEP 5:

  • Run it!

I'm not going into details about any of the code as the two links at the top do that very well. This is just about having complete, simple, clean code that you can build on. Enjoy.

Swipe Table Cells overlapping cell content on swipe motion

I actually resolved this issue - i needed to add the labels to the contentView, not the actual view.

so the code should have been

self.contentView.addSubview(name) 

for example, on the custom tableviewcell

How to enable swipe to delete cell in a TableView?

You don't have to set editing:YES if you need to show Delete button on cell swipe. You have to implement tableView:canEditRowAtIndexPath: and return YES from there for rows you need to edit/delete. This is not necessary when your tableView's dataSource is a subclass of UITableViewContoller - this method, if not overridden, returns YES by default. In all other cases you have to implement it.

EDIT: Together we have found the problem - tableView:editingStyleForRowAtIndexPath: returned UITableViewCellEditingStyleNone if table wasn't in editing mode.

How to edit tableview cell on TAP instead of swipe - Swift

I don't think you're going to be able to do it, sorry. This feature relies on the UITableView's pan gesture recognizer. When the user pans sideways, the table view checks the editActions... delegate method and, if we have edit actions, inserts a private confirmation view behind the cell and allows the cell to be moved to reveal it. You can't trigger that behavior programmatically as far as I can tell.

This would be a reason — one of many very good reasons — for sticking with a third-party scrollable cell class. In this way, the cell is a horizontal scroll view and you just scroll it in code.

UITableViewCell, show delete button on swipe

During startup in (-viewDidLoad or in storyboard) do:

self.tableView.allowsMultipleSelectionDuringEditing = false

Override to support conditional editing of the table view. This only needs to be implemented if you are going to be returning NO for some items. By default, all items are editable.

- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
// Return YES if you want the specified item to be editable.
return YES;
}

// Override to support editing the table view.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
//add code here for when you hit delete
}
}


Related Topics



Leave a reply



Submit