17

I know, that when I implement tableView:willBeginEditingRowAtIndexPath:and tableView:didEndEditingRowAtIndexPath:, a swipe-to-delete does not call setEditing:animated: at my UITableViewController (being the delegate of the UITableView).

I have a custom UITableViewCell implementation that does a little UI rearrangements when going to edit mode. I wanted to be smart and implemented these changes in setEditing:animated: at the table view cell implementation itself (which obviously makes sense).

However, when swiping to delete, I still get a call to setEditing:animated: at my table view cell implementation. And I have no parameter that tells me that I am swiping. The call stack also shows none of my own methods that would give me a chance to do something. It shows that setEditing:animated is called at the UITableView. The only thing obviously is, that it is not called at the delegate (my controller in this case).

Of course, I could set a flag at the cell in tableView:willBeginEditingRowAtIndexPath: that tells it that the next setEditing call will be for a swipe, but that does not sound like good style.

Edit: it doesn't even work, because it is not guaranteed that tableView:didEndEditingRowAtIndexPath: is called, so I cannot set the flag back.

Any ideas how to solve this issue elegantly?

Björn Landmesser
  • 953
  • 10
  • 26
  • I'm not sure if I understand correctly. So you still want to do something in your UITableViewCell's setEditing:animated:, right? If not, does this link help? http://stackoverflow.com/questions/969313/uitableview-disable-swipe-to-delete-but-still-have-delete-in-edit-mode – phi Jun 22 '11 at 14:41
  • I want to have swipe-to-delete enabled. But I want to be able to distinguish between "real" edit mode and the "pseudo" edit mode that is set for swipe-to-delete. In the `UITableViewDelegate` I can distinguish both, because `setEditing:animated:` is not called when swiping to delete. However I am not able to make a difference in the `UITableViewCell` implementation. Or am I somehow? – Björn Landmesser Jun 24 '11 at 17:05

5 Answers5

25

I think UITableViewCell's willTransitionToState: instance method may be what you are looking for. Something like this:

- (void)willTransitionToState:(UITableViewCellStateMask)state
{
    if (state == UITableViewCellStateShowingDeleteConfirmationMask) {
        swipedToDelete = YES; // BOOL ivar
    }
}

- (void)setEditing:(BOOL)editing animated:(BOOL)animated
{
    if (swipedToDelete) {
        // do your stuff, or don't
    }
}

Is that it?

Filip Radelic
  • 26,607
  • 8
  • 71
  • 97
  • Yes, that solves the problem of getting notified at the cell for a swipe. Thanks! Setting the flag back can be done in `willTransitionToState` in the else branch.But one problem remains: If I start editing in my table view, all cells get the `setEditing` call. Also, when I end editing but not in this situation: I swipe to delete getting the "Delete" button and then press "Edit" in my table view. Then the cells get no call to `setEditing`. That's really strange. Any ideas? – Björn Landmesser Aug 09 '11 at 11:22
  • One note: the problem when debugging is that the `setEditing:animated:` of the cells is triggered via the `UITableViewController`'s implementation of `setEditing:animated:` (in my case a `[super setEditing:editing]`). So, I can just guess that the cells are notified, because there is one cell with `editing == YES`. – Björn Landmesser Aug 09 '11 at 11:56
  • May Apple had the same problem with this in the contacts app. They "solved" it by changing the "Edit" button into a "Done" button, so there is no way into edit mode from the delete confirmation state. – Björn Landmesser Aug 12 '11 at 08:47
  • 4
    If you add [super willTransitionToState:state]; in your code you preserve the common cell behavior. Just in case someone (like me) copy and pastes this method and wonders why the icons in the cell disappeared.. ;) – Raphael Apr 02 '13 at 12:24
  • 1
    As Raphael said, add [super willTransitionToState:state]; – Jason Apr 08 '13 at 08:50
6

I know this has probably been done to death, but the solutions presented didn't seem to be a complete simple answer, nor did they seem to provide good example code, so I thought I'd add my answer.

Add to your class a private instance variable:

@implementation MyTableViewController {
    BOOL _cellSwiped;
}

Override the setEditing method to look for the _cellSwiped variable and only propagate if we didn't swipe. The part that people seem to be missing is that _cellSwiped needs to be reset back to NO otherwise you will never be able to use the edit button after swiping!

- (void) setEditing:(BOOL)editing animated:(BOOL)animated {
    if (!_cellSwiped) {
        [super setEditing:editing animated:animated];
    } else if (!editing) {
        _cellSwiped = NO;
    }
}

Finally, add this method override to detect the swipe:

- (void)tableView:(UITableView *)tableView willBeginEditingRowAtIndexPath:(NSIndexPath *)indexPath {
    _cellSwiped = YES;
}
Kudit
  • 4,212
  • 2
  • 26
  • 32
3

This is an old question, but I'm wondering why nobody seems to be aware of the fact that there is a showingDeleteConfirmation property built right into UITableViewCell (since iOS 2.0):

- (void)setEditing:(BOOL)editing animated:(BOOL)animated
{
    [super setEditing:editing animated:animated];

    BOOL reallyEditing = editing && !self.showingDeleteConfirmation;
    // [...]
}

No need to override -willTransitionToState: and manually keep track of the state.

Daniel Rinser
  • 8,855
  • 4
  • 41
  • 39
  • 1
    At that point, `showingDeleteConfirmation` is actually NO and gets set somewhere after `setEditing:animated:` call. – Denys Stas Jan 23 '16 at 06:51
3

What I do is something like this:

- (void)tableView:(UITableView *)tableView willBeginEditingRowAtIndexPath:(NSIndexPath *)indexPath
{
    cellSwiped = YES;
    self.editing = NO;
}

Then in the

- (void)setEditing:(BOOL)editing animated:(BOOL)animated 

method I simply check to see if the cellSwiped ivar is set and modify the UI accordingly.

AlexRpo
  • 31
  • 2
2
- (void)tableView:(UITableView *)tableview commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {

    if(editingStyle != UITableViewCellEditingStyleDelete) {
       // add code here

    }
}

When called, this method will perform the following operations

UITableViewCellEditingStyleNone,
UITableViewCellEditingStyleDelete,
UITableViewCellEditingStyleInsert

If you don't want the swipe option you can set the bool variable in the delegate method

- (void)willTransitionToState:(UITableViewCellStateMask)state

willTransitionToState will be called before

commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:
dandan78
  • 13,328
  • 13
  • 64
  • 78
Srinivas
  • 983
  • 9
  • 21