How to avoid swipe to delete calling setEditing at the UITableViewCell
Asked Answered
M

5

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?

Marvellamarvellous answered 22/6, 2011 at 9:47 Comment(2)
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? #969813Upanishad
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?Togoland
M
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?

Mulvihill answered 6/8, 2011 at 15:34 Comment(5)
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?Togoland
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.Togoland
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.Togoland
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.. ;)Drewdrewett
As Raphael said, add [super willTransitionToState:state];Zwieback
A
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;
}
Alys answered 28/3, 2013 at 22:44 Comment(0)
M
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.

Meghan answered 23/7, 2011 at 2:18 Comment(1)
That's exactly what I mentioned in my question. However, this does not work reliably (see Question)Togoland
D
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.

Drucilla answered 12/2, 2015 at 11:30 Comment(1)
At that point, showingDeleteConfirmation is actually NO and gets set somewhere after setEditing:animated: call.Thuja
W
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:
Waft answered 9/8, 2011 at 5:10 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.