简体   繁体   中英

UITableViewCell “full” swipe, right-to-left

I have a UITableView with cells already implementing two custom buttons (UITableViewRowAction edit actions) when swiping right-to-left. All works well.

I'd like to trigger one of the buttons' actions when the user swipes "all the way" (also right-to-left), similar to Mail.app.

Code is Swift 3, for iOS 9 and 10.

I have what I believe to be sufficient code in place.

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

func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
    print("commit editingStyle")
}

The commit editingStyle function never fires, as I would expect it to.

I removed my editActionsForRowAt method, thinking perhaps I was screwing something up while defining the custom buttons. I now see the default "Delete" button, but commit editingStyle still does not fire.

For what it's worth, this is a UITableView inside a UIViewController (not a UITableViewController), with both .dataSource and .delegate set to the class in question. It is also a NSFetchedResultsControllerDelegate.

Attach a UISwipeGestureRecognizer to the table itself, not to the individual cells. When a swipe is detected, calculate which cell was swiped, and call your swipe action accordingly.

Add this :

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

I came up with a mechanism to do this, which I don't think is too much of a hack - certainly less-so than other solutions I found. Comments are welcome.

My intent is always to use as much standard functionality as possible. What I'm doing is to track how far a user has swiped the main body of the cell to the left. When some threshold is reached, I tell the UITableView to perform the same action called from editActionsForRowAt for the button in question.

I'm using -225 as the threshold for how far to the left the cell has been moved. This might not work for all implementations (and I may modify myself with more testing). In my case I have two custom actions, the button for one is somewhat on the wide side.

The only thing I really add is an NSTimer, which I add to the main run loop using the .UITrackingRunLoopMode. This has the benefit of running when (and only when) the user is moving their finger around. When the timer fires, I check to see where the cell is relative to the host tableView. No added views, no added gesture recognizers.

In the custom UITableViewCell, I added this:

var trackTimer:Timer? = nil
weak var tableView:StudentsLessonsViewController? = nil

override func awakeFromNib() {
    super.awakeFromNib()
    setupTimer()
}

override func prepareForReuse() {
    super.prepareForReuse()
    setupTimer()
}

func setupTimer() {
    self.trackTimer = Timer.init(timeInterval: 0.1, target: self, selector: #selector(performActionIfScrolledFarEnough), userInfo: nil, repeats: true)
    if let trackTimer = self.trackTimer {
        RunLoop.main.add(trackTimer, forMode: .UITrackingRunLoopMode)
    }
}

func performActionIfScrolledFarEnough() {
    let globalPoint = self.superview?.convert(self.frame.origin, to: self.tableView?.tableView)
    //print("globalPoint.x: \(String(describing: globalPoint?.x))")
    if let globalPoint = globalPoint {
        if globalPoint.x < CGFloat(-225) {
            //print ("Perform Action NOW!!!")
            trackTimer?.invalidate()
            if let tableView = self.tableView {
                tableView.primaryActionButtonPressed(cell: self)
            }
        }
    }
}

In the UITableView's cellForRowAtIndexPath, I added:

cell?.tableView = self

I already had this function in my UITableView, which I was calling when the user taps one of the buttons defined in editActionsForRowAt:

func tableView.primaryActionButtonPressed(cell:UITableViewCell)

In my primaryActionButtonPressed function I remove the cell from the tableView (conceptually like a delete). It's possible dissimilar actions might require different implementation details.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM