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

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!

Related

how to begin moving cell with long press gesture?

I have a UITableView with several UITableViewCells in it. I'd like to long press on a cell to begin move it and keep holding on it and drag to move it. But i don't know how.
I added a long press gesture on table view, when user long pressed , set tableview's editing to YES:
UILongPressGestureRecognizer *longPressRecognizer = [[UILongPressGestureRecognizer alloc]
initWithTarget:self
action:#selector(handleTableViewLongPress:)];
[_tableView addGestureRecognizer:longPressRecognizer];
- (void)handleTableViewLongPress:(UILongPressGestureRecognizer *)gesture
{
if (gesture.state != UIGestureRecognizerStateBegan)
return;
[_tableView setEditing:YES];
}
And the tableview could move cell with two methods:
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
{
return YES;
}
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath
{
//update datasource
}
But with these code user must use two touch to move a cell: one is to set the tableview to editing state, another is to move cell. What i want is to allow user use one touch to do this.
Any suggestions? thanks!
I have found this UITableView subclass: Move table view

How to avoid swipe to delete calling setEditing at the UITableViewCell

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:

Edit & delete multiple rows in UITableView simultaneously

In my app I need to delete multiple rows in a table, edit the table and get a check box beside the table. When checked then the table cells are deleted. It is like the iPhone message app. How can I do this, please help me.
If I understand your question correctly, you essentially want to mark UITableViewCells in some way (a checkmark); then, when the user taps a master "Delete" button, all marked UITableViewCells are deleted from the UITableView along with their corresponding data source objects.
To implement the checkmark portion, you might consider toggling between UITableViewCellAccessoryCheckmark and UITableViewCellAccessoryNone for the UITableViewCell's accessory property. Handle touches in the following UITableViewController delegate method:
- (void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *c = [tableView cellForRowAtIndexPath:indexPath];
if (c.accessoryType == UITableViewCellAccessoryCheckmark) {
[c setAccessoryType:UITableViewCellAccessoryNone];
}
//else do the opposite
}
You might also look at this post regarding custom UITableViewCells if you're wanting a more complex checkmark.
You can set up a master "Delete" button two ways:
The IB approach
The programmatic approach
In either case, eventually a method must be called when the master "Delete" button is pressed. That method just needs to loop through the UITableViewCells in the UITableView and determined which ones are marked. If marked, delete them. Assuming just one section:
NSMutableArray *cellIndicesToBeDeleted = [[NSMutableArray alloc] init];
for (int i = 0; i < [tableView numberOfRowsInSection:0]; i++) {
NSIndexPath *p = [NSIndexPath indexPathWithIndex:i];
if ([[tableView cellForRowAtIndexPath:p] accessoryType] ==
UITableViewCellAccessoryCheckmark) {
[cellIndicesToBeDeleted addObject:p];
/*
perform deletion on data source
object here with i as the index
for whatever array-like structure
you're using to house the data
objects behind your UITableViewCells
*/
}
}
[tableView deleteRowsAtIndexPaths:cellIndicesToBeDeleted
withRowAnimation:UITableViewRowAnimationLeft];
[cellIndicesToBeDeleted release];
Assuming by "edit" you mean "delete a single UITableViewCell" or "move a single UITableViewCell," you can implement the following methods in the UITableViewController:
- (void)viewDidLoad {
[super viewDidLoad];
// This line gives you the Edit button that automatically comes with a UITableView
// You'll need to make sure you are showing the UINavigationBar for this button to appear
// Of course, you could use other buttons/#selectors to handle this too
self.navigationItem.rightBarButtonItem = self.editButtonItem;
}
// Override to support conditional editing of the table view.
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
// Return NO if you do not want the specified item to be editable.
return YES;
}
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath {
return YES;
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
//perform similar delete action as above but for one cell
}
}
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath {
//handle movement of UITableViewCells here
//UITableView cells don't just swap places; one moves directly to an index, others shift by 1 position.
}
You can put 1 UIButton lets call it "EDIT" and wire up it to IBAction. In IBAction write so you will be able to do as per your requirement.
-(IBAction)editTableForDeletingRow
{
[yourUITableViewNmae setEditing:editing animated:YES];
}
This will add round red buttons on the left hand corner and you can click on that Delete button will appear click on that and row will be deleted.
You can implement delegate method of UITableView as following.
-(UITableViewCellEditingStyle)tableView: (UITableView *)tableView editingStyleForRowAtIndexPath: (NSIndexPath *)indexPath
{
//Do needed stuff here. Like removing values from stored NSMutableArray or UITableView datasource
}
Hope it helps.
you want to be looking for deleteRowsAtIndexPath, with all your code squeezed between [yourTable beginUpdates] & [yourTable endUpdates];

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

how to detect touch event in table cells for iphone

how to detect touch event for table cells
i tried this
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
//<my stuff>
[super touchesBegan:touches withEvent:event];
}
but its not working actuallly i have aUIimage view in table cell and i want to chnage imgae based on tap so my touch event is not working for that cell
If you want to detect a touch on the UITableViewCell you don't really need to detect touch events. In your UITableViewController subclass, you need to implement the following delegate method:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath;
Then you modify the image of the table cell for the selected index path.
You probably need to set myImageView.userInteractionEnabled = YES;.
In one of my projects I needed any tap on the tableView to dismiss the keyboard so the underlying tableView would show. Since a UITableView is really a UIScrollView, it will respond to the scrollView delegate methods. Using these 2 methods will dismiss if either the user taps on a cell or scrolls the tableView at all:
IMPORTANT: Make sure you implement the UIScrollViewDelegate in your .h file as well as the UITableViewDelegate and UITableViewDataSourceDelegate!!!
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
//remove keyboard if table row is clicked
if ([self.firstName isFirstResponder] || [self.lastName isFirstResponder]) {
[tableView deselectRowAtIndexPath:indexPath animated:NO];
[self.firstName resignFirstResponder];
[self.lastName resignFirstResponder];
}
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
//remove keyboard if table scrolls
if ([self.firstName isFirstResponder] || [self.lastName isFirstResponder]) {
[self.firstName resignFirstResponder];
[self.lastName resignFirstResponder];
}
}