Disable user interaction when didSelectRowIndexPathRow is called - ios

So when the user selects a row, I put the selection on another thread for performance reasons. When I take it off of the main thread, the row is deselected for a few seconds and the pushed to the next view. Those few seconds when the row is deselected and taken off of the main thread, the user has the option to rapidly click the row again, and again - forcing the app to potentially crash. So my question is how would I deselect user interaction on the table row inside of the didSelectRowAtIndexPath method? Now, please acknowledge I don't want to disable user interaction before the a row is selected. I only am looking to disable user interaction on the cell after the row has been selected. Thanks!

Make an instance variable NSIndexPath selectedPath;
Add
[[self.tableView cellForRowAtIndexPath:indexPath] setUserInteractionEnabled:NO];
selectedPath = indexPath;
to your didSelectRowAtIndexPath and in performSegueWithIdentifier (assuming you are using storyboards) add
[[self.tableView cellForRowAtIndexPath:self.selectedPath] setUserInteractionEnabled:YES];

Related

Trying to make a table cell return to its original state after swipe to reveal in iOS

I have a UITableView where I am using the swipe to delete feature to give the user the option to delete the row. However, I've also implemented an alert view that is triggered when the user selects delete, asking the user if they are sure, with two buttons, yes or no. If the user presses yes, the row is deleted, and this is working fine.
However, my problem is that when the user selects no, I am unable to animate the movement of the table cell to return to it's normal, original state while hiding the delete button that it revealed. My problem is that I want the row to do this after the user presses no on the alert, and for the animation to smooth, just as it worked when the user swiped it initially.
The code I have is the following:
- (void) cancelDelete {
//[self.tableView reloadData];
//NSLog(#"the indexpath is: %# ", self.myIndexPath);
//[self.tableView deselectRowAtIndexPath:self.myIndexPath animated:YES];
[self.tableView reloadRowsAtIndexPaths:#[self.deletedRowIndexPath] withRowAnimation:UITableViewRowAnimationRight];
}
I have left the commented lines in place to show you what I have used/am using.
[self.tableView reloadData] returns the cell back to it's original state, but there is no sliding animation of the cell to the right, such that it gradually hides the delete button. [self.tableView reloadRowsAtIndexPaths:#[self.myIndexPath] withRowAnimation:UITableViewRowAnimationRight] is what works the closest, but unfortunately, it causes the cell to jerk to the left, and then slide to the right, and I don't want this initial jerking movement. I honestly thought that [self.tableView deselectRowAtIndexPath:self.myIndexPath animated:YES] would work, but unfortunately, it doesn't do anything when it is called. What is it I am doing wrong?
Reloading is completely the wrong strategy (as you've discovered). Swiping to delete has put the table view cell into editing mode. What you want to do is put it back again so that it is no longer in editing mode.
There are various ways to do this. You might be able to call tableView:commitEditingStyle:forRowAtIndexPath:. You might be able to call setEditing:animated:. In any case, abandon your concentration on reload (which is about data) and start experimenting with editing mode.

Hide Delete button from UITableViewCell

When my table view is in edit mode, the red (-) buttons appear.
When the user taps one of them the [Delete] button appears.
When the user taps on [Delete] I first check a few things (partly online). This delete may not be allowed.
When deleting that cell is not allowed, how do I hide the [Delete] button and let the red (|) button become a (-) again in an animated way? So, I don't want my whole table to leave editing state.
To get the actual animation (Instead of the UITableViewRowAnimationRight/UITableViewRowAnimationAutomatic) animations, just do
[self.tableView beginUpdates];
[self.tableView setEditing:NO animated:NO];
[self.tableView setEditing:YES animated:NO];
[self.tableView endUpdates];
beginUpdates and endUpdates provide the animation, and the tableView is just switched from not editing to editing instantly, which closes the delete button.
Hope this helps!
I've run into this issue myself where I may bring up an alert view to prompt the user further and wish to reset the delete button if they choose not to proceed. This seems like the easiest approach, assuming deleteIndexPath is the index path of the row selected for deletion:
[self.tableView reloadRowsAtIndexPaths:#[deleteIndexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
I now see that you want to disable delete for only certain cells. You can do this in a couple of ways:
tableView:canEditRowAtIndexPath method: Return NO where you want DELETES to be DISABLED.
tableView:canMoveRowAtIndexPath: Return YES where you want to allow reordering.
You may want to think about sub-classing UITableViewCell to give it some ability to maintain its own state (so the cell knows if delete is allowed or not. Then you can interrogate the actual cell instance and determine if you should enable delete even after the list may be re-ordered.
To hide any icon in whole table view, then in your controller just ,
override EditingStyleForRow and return UITableViewCellEditingStyle.None
None: will hide any icon of left of items of table view,
delete: will show remove icon
Insert: will show add icon

tableView:didDeselectRowAtIndexPath: not called until first user-initiated selection and deselection

I have a UITableView with four cells, in single selection mode. When the view is first loaded, I programmatically select one of the cells using -selectRowAtIndexPath:animated:scrollPosition: based on a stored preference. After this, the user can interact with the table.
The methods -tableView:willSelectRowAtIndexPath: and -tableView:didSelectRowAtIndexPath: are called on my table view delegate every time the user taps any cell. However, -tableView:willDeselectRowAtIndexPath: and -tableView:didDeselectRowAtIndexPath: (that's DEselect) don't start being called until the user manually taps that first programmatically selected cell.
Any idea why this might be happening? Are there any workarounds besides manually calling -[UITableView selectRowAtIndexPath:animated:] for every cell except the one that the user tapped?
If you do invoke [UITableView selectRowAtIndexPath:animated:] too soon and you are using a UITableViewController, you probably have conflict with the UIViewController clearsSelectionOnViewWillAppear (defaults to YES). Try setting self.clearsSelectionOnViewWillAppear = NO; in your viewDidLoad
This is too long for comment so I'm posting this as an answer.
Just created test project with tableView. I call [UITableView selectRowAtIndexPath:animated:] on viewDidLoad and I have one cell selected. Then I'm selecting another cell (without deselecting first one).
I have this output:
[SDTVTViewController tableView:willSelectRowAtIndexPath:]
[SDTVTViewController tableView:willDeselectRowAtIndexPath:]
[SDTVTViewController tableView:didDeselectRowAtIndexPath:]
[SDTVTViewController tableView:didSelectRowAtIndexPath:]
And I have first cell deselected and second one selected.
I have no idea, why it's not working in your code. When you're calling [UITableView selectRowAtIndexPath:animated:] and can you post code of UITableViewDelegate methods that you've implemented?
I was wrapping my initial data source updates and -selectRowAtIndexPath:... calls in
[_tableView beginUpdates];
// ...
[_tableView endUpdates];
Apparently, like -reloadData, this clears the current selection (not sure if that's by design). I moved the call to -selectRowAtIndexPath:... to after -endUpdates and now everything works as intended.

How to know that no row is selected in my UITableView?

I use a UITableView to display a list of items, and when a row is selected I show that item in a detail view next to it (using a split view controller).
As the selection in the table view changes I want my detail view to change as well, which is of course standard behavior and it works flawlessly... except when no row is selected anymore in the table view.
Users can for example delete a row from the table view, and during and also after that deletion there will be no selected row in the table view. Of course after a row is deleted I let my detail view controller know, but during the editing process in the table view, when no row is selected, my detail view controller does not know this.
I tried to use the UITableViewSelectionDidChangeNotification but that only gets sent when the user selects a different row, not when a deselection occurs.
How can I be notified of the fact that the table view switches from having a row selected to having no selection at all?
EDIT:
As a temporary solution, I tried renaming the Edit-button to "Reorder" and only allowing moving rows from A to B but without allowing the deletion controls, but this can not be done, there is no move control without enabling editing on a row. The thing is, I do get a pointer to a row that is up for moving, so I can keep that selected. I do not get this pointer for a row up for deletion, so no go for me. I always want to know what row a user works on, and keep that row selected at all times.
I may have to resort to ditching the standard editing behavior and adding my own buttons and methods for it. Or see what gestures can do for me to capture touches on any row...
There is a property indexPathForSelectedRow. I'm not sure what it would return when there is no selected row, but it may return nil or something like that, which you could use as a trigger to know if there are any rows selected. Something like
if (myTable.indexPathForSelectedRow == nil)
{
//do something here to account for no rows being selected
}
else
{
//do stuff here to set up your detail view
}
Let me know if this works for you.
How are you implementing the deletion of rows? Are you implementing the following data source method?
tableView:commitEditingStyle:forRowAtIndexPath:
You can have a property like
NSIndexPath *selectedIndexPath
and set it to nil when a row is being deleted.
Example:
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
//select another row in your table
[tableView selectRowAtIndexPath:*indexPathOfTheRowToBeSelected* animated:YES scrollPosition:UITableViewScrollPositionNone];
//then delete row from data source
}
The method above will be called when the user touches the delete button on the table he/she has selected to delete.
Okay I misread what you were asking at first, I'm pretty sure what you want is either – tableView:willDeselectRowAtIndexPath: or – tableView:didDeselectRowAtIndexPath:. These methods will be triggered automatically when the user deselects a row (either right before the row is deselected or right after, respectively). Implement one of these in your table view delegates code, and you'll know whenever a row gets deselected, and you can put your code to select the next row or whatever you want in one of these methods.
I struggled with this as well. Turns out that when the "Edit" button is hit, all rows are deselected at that point. You can override setEditing:animated: to detect when it is hit, but you must call [super setEditing:editing animated:animated] before you return.
See this link for where I found this:
How can i identify self.editButtonItem button's clicked event?

Have UITableView row selected rather than just highlighted

I currently set the selected row of a UITable via
selectRowAtIndexPath:animated:scrollPosition:
and as described in the documentation, this does not call
tableView:didSelectRowAtIndexPath:
so I have set up a selector call to perform this action.
However, the end result is that the row in the table is highlighted, but not selected. When I touch the highlighted row, the font color changes to white.
Is there a way to not only highlight, but also have the row "selected" so tapping that row again does not result in any changes or updates?
Try calling didSelectRowAtIndexPath directly and then scrolling to it. I have this in a UITableViewController and it works fine (and the selection event does not fire again when you tap on it, I just tested it). I'm wondering if there is some other code messing you up.
[self tableView:self.tableView didSelectRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]];

Resources