I am working with the kind of notes app and I wanted to add the option to swipe-to-delete (like the iPhone's default notes app). I implemented the following two table view methods..
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
return YES;
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete)
{
//Action to delete value of the cell
}
}
Everything works well except an animation. Showing the delete button on swipe action happens with an animation while hiding it (by tapping or scrolling table view) does not happens with the animation. The delete button was just disappeared immediately.
Can I show the hiding process of the delete button with animation?
For fully control on editing in your custom cell, you should override willTransitionToState method in your UITableViewCell subclass and check state mask
- (void)willTransitionToState:(UITableViewCellStateMask)state
{
NSString *logStr = #"Invoked";
if ((state & UITableViewCellStateShowingEditControlMask)
!= 0) {
// you need to move the controls in left
logStr = [NSString stringWithFormat:#"%#
%#",logStr,#"UITableViewCellStateShowingEditControlMask"];
}
if ((state & UITableViewCellStateShowingDeleteConfirmationMask)
!= 0) {
// you need to hide the controls for the delete button
logStr = [NSString stringWithFormat:#"%#
%#",logStr,#"UITableViewCellStateShowingDeleteConfirmationMask"];
}
NSLog(#"%#",logStr);
[super willTransitionToState:state];
}
EDIT:
Did you try:
setEditing:animated:
Toggles the receiver into and out of editing mode.
(void)setEditing:(BOOL)editing animated:(BOOL)animated
Parameters
editing
YES to enter editing mode, NO to leave it. The default value is NO .
animated
YES to animate the appearance or disappearance of the insertion/deletion control and the reordering control, NO to make the transition immediate.
Discussion
When you call this method with the value of editing set to YES, and the UITableViewCell object is configured to have controls, the cell shows an insertion (green plus) or deletion control (red minus) on the left side of each cell and a reordering control on the right side. This method is called on each visible cell when the setEditing:animated: method of UITableView is invoked. Calling this method with editing set to NO removes the controls from the cell.
Availability
Available in iOS 2.0 and later.
See Also
#property editing
Declared In
UITableViewCell.h
Related
In an iOS apps I have a table view that has 2 rows with textfield embedded inside.
Textfield2 is a textfield with pickerview input that I set with something like this:
textField2.inputView = pickerView;
So the thing is , the textField 2 icon on the right is only an image embedded in the textfield2.rightview that caused the image to not trigger the pickerView input when tapped.
Did select table view method also wasn't triggered because I set the textfield to fully occupy the cell. Thus, after some searching I find that disabling the textField2 user interaction enabling the didSelect to be triggered.
textField2.userInteractionEnabled = false;
However, now I'm at lost on to how to trigger the input to textField2 pickerView via the didselect tableview method. I tried this line of code but that doesn't work.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(#"Did select row %d",indexPath.row);
if(indexPath.row == 1){
[textField2 becomeFirstResponder];
}
}
I tried to search how to trigger input manually to textField and didn't find any clue.
Thanks before ! :)
After some debugging with a clear mind, I find that
textField2.userInteractionEnabled = false;
caused the textfield not able be the responder.
So a little workaround with this flag is enable it first in order to edit the text field and disable it again after we finished editing. Something like this :
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(#"Did select row %d",indexPath.row);
if(indexPath.row == 1){
[textField2.userInteractionEnabled = true;
[textField2 becomeFirstResponder];
}
}
- (void)donePicker {
// to enable the did select row again
[textField2.userInteractionEnabled = true;
}
I have two table view controllers, "root" and "detail". In my root view I have this cell which says "Status". I need to be able to change that. When I click it i am seguewayd to the detailed view which shows the statuses I can pick (static cells). When I click on a status, a checkmark is displayed. But this checkmark also needs to be displayed when a status is previously chosen. So the checkmark should be visible as soon as I am seguawayd in from the root view.
I am able to display a checkmark next to the status as soon as i click a cell. But when I want the checkmark to be displayed when i'm seguawayd, it doesn't show. This is the code im using
- (void) setCheckmarkOnIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self setCheckmarkOnIndexPath:indexPath];
}
- (void)viewDidLoad
{
[super viewDidLoad];
// indexPathForRow set to the third cell to demo
[self setCheckmarkOnIndexPath:[NSIndexPath indexPathForRow:2 inSection:0]];
}
You need to store the user selection somewhere, and pass it into your controller (or access it in your controller depending on where it's saved and which object owns that information).
Currently, you don't save the user selection so you can't update the cell. Note also that you should be updating the selected cell in viewDidAppear:, not viewDidLoad, and that you should look at using tableView:willDisplayCell:forRowAtIndexPath: to properly deal with the table view being scrolled (and cells being replaced / reused).
If you notice in the iPad contacts app when you tap on the "+" edit icon to add a new address, the cell does not expand to the left when the icon disappears (see 1st screen capture below). I am trying to do something similar but am having no luck (see 2nd screen capture below). I tried using the solution suggested here but didn't work.
For the record I am not trying to replicate the actual contacts app or integrate with contacts. We're working on something unrelated and my designer just wants to follow this pattern so doing some POC work to see what I can do.
EDIT - Another question, to verify my thinking, is that in the contacts app here what's happening is when the "+" icon is tapped, this cell is set to not editing any more, these text fields are added to the cell, the label changed, and then reloadData is called, right?
EDIT - Thanks for the suggestion Tim, I'm almost there! I had actually worked out 1/2 of it but then was running into the issue that the "+" icon was not animating out, just abruptly disappearing. So I added the reloadRows... call to commitEditingStyle but now the entire cell disappears. Here is my code:
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCellEditingStyle editingStyle = UITableViewCellEditingStyleNone;
if (self.showEditingIcon) {
editingStyle = UITableViewCellEditingStyleInsert;
self.showEditingIcon = NO;
}
return editingStyle;
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
// tableView.editing = NO;
// tableView.editing = YES;
[self.tableView reloadRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
You can see from my commented-out lines what I had originally, which was working but as I said, was not animating - the "+" button was just abruptly disappearing. If I tried to call [tableView setEditing:NO animated:YES] it would not work. When I tried to put these calls within a UIView animation block it did not look good - could see cell temporarily shift to left and back. However now with the reload call the cell disappears completely. At the moment I'm not making any changes to my cell (for example I'm not adding text fields, etc...) because I just want to make the "+" button animating out without making the cell expand the left work on the first iteration.
Any help greatly appreciated. Thanks.
The trick is to always be in editing mode such that the cell indention remains constant. When the cell is loaded, you decide what state it is in and return the appropriate editing style, either the "insert" style or "none":
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
{
BOOL shouldShowInsertButton = ...;//check internal state for cell
return shouldShowInsertButton ? UITableViewCellEditingStyleInsert : UITableViewCellEditingStyleNone;
}
Then when the edit button is tapped, you update your internal state and reload the cell:
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
...;//update internal state for cell
[self.tableView reloadRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
EDIT
Here's a working sample project.
I have a UITextField with a tag inside a prototype cell. The UITextField is set to become first responder when the UITableView is being built and a UISwitch in the cell above is turned on.
This works if the app starts from scratch or if it was closed and restarted. Once it's loaded the [tableView reloadData] doesn't trigger the becomeFirstResponder anymore.
If the UITextField becomes first responder by touching the textfield later on, I can trigger the becomeFirstResponder event with buttons, with pop ups,...
But not with my switch any more.
Any pointers as to what I can try?
Currently, I use the didSelectRowAtIndexPath method to trigger a pop up. A nice side effect is, that when I pull up the number keypad, I can provide an ok and cancel button within the pop up instead of having to fiddle with separate buttons on the keypad. But it just seems so obviously to be a workaround.
This is how I call firstresponder when building the UITableView (which works every time the app starts from scratch):
if ([settings doubleForKey:#"limitDouble"]==0 && [settings boolForKey:#"limitBool"]==YES) {
[dailyLimitEntry becomeFirstResponder];
}
dailyLimitEntry is a UITextField which is strong so it stays around.
Just for fun I added a button and connected it to my code like this:
UITextField *tmp = (UITextField *)[self.view viewWithTag:35];
[tmp becomeFirstResponder];
This works, too. When I use it with the switch, it's only called once the app is freshly loaded in the memory. Otherwise, my UITextField doesn't respond to the switch.
After the first comments, I found a method to check whether or not the UITableView has finished reloading
-(void) tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
if([indexPath row] == ((NSIndexPath*)[[settingsTableView indexPathsForVisibleRows] lastObject]).row){
//end of loading
//for example [activityIndicator stopAnimating];
NSLog(#"finished reload");
NSLog(#"%#",dailyLimitEntry);
if ([settings boolForKey:#"limitBool"]==YES) {
UITextField *tmp = (UITextField *)[self.view viewWithTag:35];
[tmp becomeFirstResponder];
}
}
}
Fun thing though is, become first responder is only triggered the first time the switch is used after the app loaded. Initially, the switch is off. So the cell containing the UITextField is not drawn yet. Once I switch to ON, the UITextField gets drawn in the second cell and becomes first responder. If I switch OFF and ON again, I still get my log "finished reload", but the UITextField doesn't become first responder. It's driving me nuts....
Must be something about the life cycle of the app.
Rather than checking the indexPath, check the cell's class.
Here's what I do to bring up the keyboard for a title cell that's blank (when I create a new item):
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([cell isKindOfClass:[FDSSampleTitleCell class]]) {
FDSSampleTitleCell *titleCell = (FDSSampleTitleCell *)cell;
if (titleCell.titleField.text.length == 0) {
[titleCell.titleField becomeFirstResponder];
}
}
}
I have a simple grouped uitableview with a nav bar and an "Edit" nav bar item. the Edit button applies only to the first section, and the other sections of the table do totally different things (think iPhone Settings). My problem is with deleting the last cell of this particular section of the table. Whenever the user deletes the last cell, I am removing the "Edit" button from the nav bar (Cause its not applicable anymore...).
So I do this:
- (void)tableView:(UITableView *)aTableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
.....
if ([section count] == 0) {
self.navigationItem.rightBarButtonItem = nil;
.....
}
.....
}
The problem is that now the other sections are not functional, meaning, I cant click on them anymore and they dont react. I think it's because I did not click on "Done" on the nav bar cause this one was deleted after deleting the last cell, so I am basically still in "editing mode" (not sure if i am right here..).
In any case, I tried to call setEditing:animated: manually after deleting the last cell, but that doesnt help.
For reference:
- (void)setEditing:(BOOL)editing animated:(BOOL)animated {
NSLog(#"****************** entering setEditing:animated");
[super setEditing:editing animated:animated];
[tblSimpleTable setEditing:editing animated:animated];
}
Any help with this would be much appreciated. Thanks!
Have you tried UITableView* method reloadSections:withRowAnimation:
after
[tblSimpleTable setEditing:editing animated:animated];
?
Works fine on iOS 5. Might be buggy on lower versions.