How to avoid swipe to delete calling setEditing at the UITableViewCell - iphone

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?

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?

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;
}

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.

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.

- (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:

Related

Why does UITableView's swipe delete sometimes work fine & sometimes not?

There is a UITableView on my view, I want to apply swipe-delete-mode rows of a certain section. What I have implemented is as follows:
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#">> canEditRowAtIndexPath");
if (indexPath.section == CanDeletedSection) {
return YES;
}else{
return NO;
}
}
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#">> editingStyleForRowAtIndexPath");
if (indexPath.section == CanDeletedSection) {
return UITableViewCellEditingStyleDelete;
}
return UITableViewCellEditingStyleNone;
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#">> commitEditingStyle");
if (editingStyle == UITableViewCellEditingStyleDelete) {
// dosomething
}
}
But when I swipe the table row, sometimes the Delete button appears, sometimes not.
Incidentally, my cell is customized and inherits from UITableViewCell.
I have added the NSLog to above methods. When the Delete button not appears the log I got like this:
>> editingStyleForRowAtIndexPath
>> canEditRowAtIndexPath
When the Delete button appears, the log as below:
>> editingStyleForRowAtIndexPath
>> canEditRowAtIndexPath
>> editingStyleForRowAtIndexPath
>> canEditRowAtIndexPath
>> canEditRowAtIndexPath
>> editingStyleForRowAtIndexPath
I have made a demo that using the customized cell, it works fine. So the problems are caused by the view controller which contains the table view. The view controller inherits from another view controller, in that view controller, there is a tap gesture which used to hide the keyboard. But when I removed them from the view controller, the result is same.
Please check whether view or superview has any other gestures. If so, make sure that you implement below method of UIGestureRecognizerDelegate after setting gesture delegate:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
return YES;
}
Sometimes, especially in the simulator, it is difficult to perform the swipe correctly. You will find that it is most likely a physical, not a coding problem.
Also, you might want to check if you custom cell does not contain an element that catches the swipe and does not pass it on to the cell.
I have also faced this same issue...
But finally I got solution by :- Example:-
self.navigationController.interactivePopGestureRecognizer.enabled = NO;
You have to Disable any other gesture in that particular view if you are using "commitcommiteditingstyle"..
Hope this will help you... :)
Gesture recognizers elsewhere in the view hierarchy can intercept and block the swipe action.
I solved it with this category in the view controller:
#interface UIView (CellSwipeAdditions)
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer;
#end
#implementation UIView (CellSwipeAdditions)
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
return YES;
}
#end
Thanks to bademi for leading me to this solution!

Redrawing UITableViewCell when entering/exiting edit mode

I have a table view in which the cells are built differently depending on whether the table is editing or not. Specifically, the selection style is none when in edit mode and blue when not in edit mode.
When I transition from one to the other, I noticed that some of the cells are not updated. A quick bit of logging tells me that even though the cells' appearance changes quite drastically (accessory views are added/removed correctly for example) the table view does not refresh the selection style (nor for that matter the text).
What is going on here? Are only some attributes of the cell updated when setEditing is called? Presumably only those with a specific method allowing allocation of a separate view style (for example the EditingAccessoryType)? I guess I would benefit from a EditingSelectionStyle.
How should I resolve it? By customizing setEditing to change the selectionStyle for each cell? I'm not even sure how I would iterate through the table view to do this. reloadData isn't an option because of some animation that I am using.
I found that customizing setEditing: to iterate through the visible cells and setting the selectionStyle for each to work ok.
- (void)setEditing:(BOOL)editing animated:(BOOL)animated{
[super setEditing:editing animated:animated];
for (UITableViewCell *cell in [self.tableView visibleCells]) {
NSIndexPath *path = [self.tableView indexPathForCell:cell];
cell.selectionStyle = (self.editing && (path.row > 1 || path.section == 0)) ? UITableViewCellSelectionStyleNone : UITableViewCellSelectionStyleBlue;
}
}
If you look at the UITableViewDelegate documentation you will see a that there are five methods to customize the editing behavior. There is also the method
- (BOOL)tableView:(UITableView *)tableView
canEditRowAtIndexPath:(NSIndexPath *)indexPath
in the UITableViewDataSource documentation that will be called on each cell before you go into editing mode. The same is true for
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView
editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
that will get called for all cells that are editable. If you want to change the way the cells look you could do it in either of these. (Not implementing canEditRow.. assumes all rows are editable.)
Also note that there may be other ways to enter editing mode such as swiping on a cell, in which case
- (void)tableView:(UITableView *)tableView
willBeginEditingRowAtIndexPath:(NSIndexPath *)indexPath
will be called for the cell that you swiped on:
When entering this "swipe to delete" editing mode, the table view sends a tableView:willBeginEditingRowAtIndexPath: message to the delegate to allow it to adjust its user interface.
This works on Swift 2.3, just overwriting the setEditing method in your custom cell subclass:
class MyCell: UITableViewCell {
override func setEditing(editing: Bool, animated: Bool) {
super.setEditing(editing, animated: animated)
//Place your code here...
}
}

iPhone: Problem with setting custom cell's accesory

I can not set the custom cells accessory view while the page loads for the first time, any ideas?
In DetailView customcell's class I have this:
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
if(self.selected)
self.accessoryType=UITableViewCellAccessoryCheckmark;
else
self.accessoryType=UITableViewCellAccessoryNone;
}
And In tableview controller:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
DetailViewCell *cell = [DetailViewCell cellForTableView:tableView];
if(somelogichere){
[cell setSelected:YES];
}
return cell;
}
I debug and hit that line so logic is true, but in debug I also see that after it sets the accesory then again it calls twice the selected method, which overrrides the accessory to none in the else inthe second call. setSelected causes the selected method to be called twice and overrides the setting on the second call cause somehow on second call self.selected returns false;
UPDATE: I solved the problem by creating a boolean cellSelected property in the custom cell class and changing and checking its status rather than setting and changing the selected property of the cell, this is also better cause I can support multi selection tableview's better in future.
Does it work the second time after the view has loaded?
It most probably has something to do with following line:
if(somelogichere){
[cell setSelected:YES];
}
What is somelogichere ?
Depending on somelogichere your selected property might not be true the first time you run your code:
if(self.selected)
self.accessoryType=UITableViewCellAccessoryCheckmark;
else
self.accessoryType=UITableViewCellAccessoryNone;
Make sure you set your cell's selected property in the beginning. Or change the code inside your setSelected.
HTH
You try this code its help u
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
[super setSelected:selected animated:animated];
UIImage *selectionBackground = [UIImage imageNamed:#"list_BG.jpg"];
UIImageView *iview=[[UIImageView alloc] initWithImage:selectionBackground];
self.selectedBackgroundView=iview;
}
OR
In cellForRowAtIndexPath method of tableView:
cell.accessoryType = UITableViewCellAccessoryCheckmark;

Left delete icons not appearing while UITableview edit mode

I have a core data/ uitableview based app. Actually 80% of the code so far is equal to the Apple Sample app CoreDataRecipes. My problem is that when I enter the edit mode (by pushing the edit button), there are no "delete badges" on the left side of the rows. Bumper.
The differences in code with CoreDataRecipes:
I have custom UITabelview cell with
a nib file instead of code only.
My Tableview is an Outlet inside my class view. So my class
RecipeListTableViewController is an
UIViewController with Tableview delegates instead of a UITableViewController
What I tried:
The Tableview works fine. There are no linking or delegate issues
I checked if the table actually
enters the edit mode. It does. You
can see that because the "Add" button
is disabled.
I checked if the editingstyle is ok. It should be by default but to make sure I added:
(UITableViewCellEditingStyle)tableView:(UITableView*)tableVieweditingStyleForRowAtIndexPath(NSIndexPath*)indexPath {return UITableViewCellEditingStyleDelete;}
I checked if the delete icons where not behind my cellview. There are not. I now think that the cell behaviour of moving to the right is handled by iOS.
When I swipe the cell, the right delete button appears and works as it should
I tried to build the behaviour my self with a layoutSubviews. Nothing changed when entering the edit mode. But when I swipe, now I see my subview in one row:
Anyone any ideas? It must be something simple.
Make sure that
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
return YES;
}
If this is not set to return YES then the badges will not be enabled. The default is set to return NO
I think you have not added the line
tableView.editing=YES on clicking the Edit button
Try by setting it!
Since yours is a UIViewController, the tableview doesnt get the setEditing call. Just add:
- (void)setEditing:(BOOL)editing animated:(BOOL)animated {
[super setEditing:editing animated:animated];
[self.tv setEditing:editing animated:YES];
}
Make sure you have setup the outlet/ delegate/ datasource
then these:
-(void)editButtonTapped
{
[self.tableView setEditing:YES animated:YES];
}
-(BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
return YES;
}
-(UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
{
return UITableViewCellEditingStyleDelete;
}

Problem in Managing the reordering og rows in UITableView

I have refered "Managing the reordering of rows" in "UITableView Programming Guide".
I have written the same code for my application for rearranging the rows of tableView but not able to rearrange the rows in tableView. The delegates "canMoveRowAtIndex" and "moveRowAtIndex" have not been called though I set tableView in editing mode through "setEditing:animated".I dont want to use core data for implementing this.
Can u provide the detailed code for this?? (I would like rearrange the rows of tableView as we do for icons by long press and then moving them)
Are you sure to add properly the "Edit" button ?
On my code (withoutcoredata), with a navigation controller, I have:
- (void)viewDidLoad {
[super viewDidLoad];
self.navigationItem.rightBarButtonItem = self.editButtonItem;
}
- (void)setEditing:(BOOL)editing animated:(BOOL)animate
{
[super setEditing:editing animated:animate];
[self.navigationItem setHidesBackButton:editing animated:YES];
}
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
{
return YES;
}
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath {
//...
}
If the methods aren't being called, chances are you either haven't set the table view instance's delegate outlet to point to your controller, or you've spelled the names of the delegate methods incorrectly.
One trick to help avoid misspellings is to go to the header file where the methods are declared (in this case, UITableViewController.h) copy the method declaration(s), and paste them into your source file. Otherwise, I try to use Xcode's completion mechanism to ensure that I don't accidentally misspell things.