I have a UITableView which lies in a NavigationController that is in a popover. So, I put an edit/done UIToolBarItem which works fine and you can see the delete accessory icon showing up. However, when I rearrange the items, the edit/done button stops working...
I debugged and it still gets called but it doesn't seem to update and is sort of preventing any further updates from other buttons. Is this possibly a problem with the simulator?
Thanks for the help in advance!
Edit: Adding code
addButton = [[UIBarButtonItem alloc] initWithTitle:#"Edit" style:UIBarButtonItemStyleBordered target:self action:#selector(editTable:)];
And later on the method:
- (IBAction) editTable: (id) sender
{
if ([[addButton title] isEqualToString:EDIT_STRING]) {
[addButton setTitle:DONE_STRING]; //enabling edit mode
[super setEditing:YES animated:YES];
[[self tableView] setEditing:YES animated:YES];
}
else {
[addButton setTitle:EDIT_STRING]; //done with editing
[[self tableView] setEditing:NO animated:YES];
[super setEditing:NO animated:YES];
[[self tableView] setNeedsDisplay];
[[self tableView] reloadData];
}
}
The second part is definitely called as the addButton text is changing. However, it stops working once I make an edit (such as re-arranging a row)
Alright,
I seemed to have called [tableView beginUpdates] and never called endUpdates, which was causing all updates to not be registered. If anyone else does that...
- (void)tableView:(UITableView *)tableview commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
[self.tv deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
[self.tv reloadData];
}
}
- (void)setEditing:(BOOL)editing animated:(BOOL)animated {
[super setEditing:editing animated:animated];
[self.tv setEditing:editing animated:YES];
}
Related
So, this issue follows on from a previous issue, but I decided to post a new question to keep things relevant and tidy.
Basically, when the following piece of code is called, there is no difference between UITableViewRowAnimationFade and UITableViewRowAnimationNone:
- (void) setEditing:(BOOL)editing animated:(BOOL)animated
{
[tvController.tableView beginUpdates];
if (editing == YES) {
[tvController.tableView deleteRowsAtIndexPaths:[settingsArray objectAtIndex:0] withRowAnimation:UITableViewRowAnimationFade];
}else {
UITableViewRowAnimation animation = animated ? UITableViewRowAnimationFade : UITableViewRowAnimationNone;
[tvController.tableView reloadRowsAtIndexPaths:[settingsArray objectAtIndex:0] withRowAnimation:animation];
[tvController.tableView reloadSectionIndexTitles];
self.navigationItem.hidesBackButton = editing;
}
[tvController.tableView endUpdates];
}
Greatly appreciate any help. It still enters editing mode, but does not animate into it, depsite YES being passed into animated.
EDIT: The animation works fine when I'm actually deleting things using the following code:
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
NSString* documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *stuff = [documentsPath stringByAppendingPathComponent:#"stuff.plist"];
BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:stuff];
if (fileExists) {
NSMutableDictionary *propertyList = [[NSMutableDictionary alloc] initWithContentsOfFile:enteredPlaces];
[propertyList removeObjectForKey:[[settingsArray objectAtIndex:1] objectAtIndex:indexPath.row]];
[propertyList writeToFile:stuff atomically:YES];
}
[[settingsArray objectAtIndex:1] removeObjectAtIndex:indexPath.row];
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationLeft];
}
}
It just doesn't work when the user presses the edit button and the table goes into editing mode, the tableview just snaps statically into edit mode.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete) {
// Delete the row from the data source
[db DeleteData:[NSString stringWithFormat:#"%d",indexPath.row]];
[data removeObjectAtIndex:indexPath.row];
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation: UITableViewRowAnimationFade];
}
}
I have same scenario in my application, I was facing the similar issue. I guess below function will solve your issue :
- (void) setEditing:(BOOL)editing animated:(BOOL)animated
{
[tvController.tableView setEditing:editing animated:animated]; //this LOC is added
[tvController.tableView beginUpdates];
if (editing == YES) {
[tvController.tableView deleteRowsAtIndexPaths:[settingsArray objectAtIndex:0] withRowAnimation:UITableViewRowAnimationFade];
} else {
UITableViewRowAnimation animation = animated ? UITableViewRowAnimationFade : UITableViewRowAnimationNone;
[tvController.tableView reloadRowsAtIndexPaths:[settingsArray objectAtIndex:0] withRowAnimation:animation];
[tvController.tableView reloadSectionIndexTitles];
self.navigationItem.hidesBackButton = editing;
}
[tvController.tableView endUpdates];
}
-(void)deleteRecord:(NSInteger)recordNo:(NSInteger)sectionNo:(BOOL)isEditMode:(BOOL)isAnimate {
if(isEditMode){
NSIndexPath *indexP=[NSIndexPath indexPathForRow:recordNo inSection:sectionNo];
[tvController.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObjects:indexP, nil] withRowAnimation:UITableViewRowAnimationLeft];
}
else {
if(isAnimate)
[tvController.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObjects:indexP, nil] withRowAnimation:UITableViewRowAnimationFade];
else
[tvController.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObjects:indexP, nil] withRowAnimation:UITableViewRowAnimationNone];
[tvController.tableView reloadSectionIndexTitles];
self.navigationItem.hidesBackButton = editing;
}
[NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:#selector(reload) userInfo:nil repeats:NO];
}
-(void)reload {
[table reloadData];
}
if the only thing that you are annoyed by is the fact that the delete doesn't fade, it is because you are anticipating something that the interface doesn't provide.
you mentioned that you know individual cells can be set to be non-editable, and this is the standard way to do this. the mechanism simply does not anticipate not using the UITableViewDataSource to provide the information about what to display (or, in your case, what is in the data being changed) simply by hitting the edit/done button.
by trying to combine the two, you are confusing the animation that is supposed to happen.
probably the best you can do is something like the following (and the animation duration and length could possibly be 0, since you're asking for separate animation in the tableView), which will cause your animation to occur after the animation that opens up editing mode.
- (void) setEditing:(BOOL)editing animated:(BOOL)animated
{
[super setEditing:editing animated:animated]; // possibly not necessary depending upon your class hierarchy
[tvController.tableView setEditing:editing animated:animated];
[UIView animateWithDuration:0.25 delay:0.05 options:UIViewAnimationCurveLinear
animations:^{
[tvController.tableView beginUpdates];
if (editing == YES) {
[tvController.tableView deleteRowsAtIndexPaths:[settingsArray objectAtIndex:0] withRowAnimation:UITableViewRowAnimationFade];
} else {
UITableViewRowAnimation animation = animated ? UITableViewRowAnimationFade : UITableViewRowAnimationNone;
[tvController.tableView reloadRowsAtIndexPaths:[settingsArray objectAtIndex:0] withRowAnimation:animation];
[tvController.tableView reloadSectionIndexTitles];
self.navigationItem.hidesBackButton = editing;
}
[tvController.tableView endUpdates];
}
completion:nil];
}
What I want to do is:
Setting editing mode on NavigationBar in UITableView adds an edit button on the left side of the UINavigationBar. When I click this button, I'd like an add button to appear on the right side of the NavigationBar.
When I click on the add button, add a row to the NSMutableArray and update the table.
So please give me ideas, code, or links to develop this functionality.
- (IBAction)DeleteButtonAction:(id)sender
{
[arry removeLastObject];
[Table reloadData];
}
- (IBAction) EditTable:(id)sender
{
if(self.editing)
{
[super setEditing:NO animated:NO];
[Table setEditing:NO animated:NO];
[Table reloadData];
[self.navigationItem.leftBarButtonItem setTitle:#"Edit"];
[self.navigationItem.leftBarButtonItem setStyle:UIBarButtonItemStylePlain];
}
else
{
[super setEditing:YES animated:YES];
[Table setEditing:YES animated:YES];
[Table reloadData];
[self.navigationItem.leftBarButtonItem setTitle:#"Done"];
[self.navigationItem.leftBarButtonItem setStyle:UIBarButtonItemStyleDone];
}
}
- (UITableViewCellEditingStyle)tableView:(UITableView *)aTableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (self.editing == NO || !indexPath) return UITableViewCellEditingStyleNone;
if (self.editing && indexPath.row == ([arry count]))
{
return UITableViewCellEditingStyleInsert;
} else
{
return UITableViewCellEditingStyleDelete;
}
return UITableViewCellEditingStyleNone;
}
- (void)tableView:(UITableView *)aTableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle
forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete)
{
[arry removeObjectAtIndex:indexPath.row];
[Table reloadData];
} else if (editingStyle == UITableViewCellEditingStyleInsert)
{
[arry insertObject:#"Tutorial" atIndex:[arry count]];
[Table reloadData];
}
}
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
{
return YES;
}
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath
toIndexPath:(NSIndexPath *)toIndexPath
{
NSString *item = [[arry objectAtIndex:fromIndexPath.row] retain];
[arry removeObject:item];
[arry insertObject:item atIndex:toIndexPath.row];
[item release];
}
}
Create a private property to have a reference to the Edit button:
#property (nonatomic) UIBarButtonItem *editButton;
In viewDidLoad:, init the button and assign it to the right button of the navigationItem:
self.editButton = [[UIBarButtonItem alloc] initWithTitle:NSLocalizedString(#"Edit", nil) style:UIBarButtonItemStylePlain target:self action:#selector(toggleEdit:)];
self.navigationItem.rightBarButtonItem = self.editButton;
Create a method to invoke when the Edit button is tapped. Will change the table's editing mode and update the Edit button title:
- (IBAction)toggleEdit:(id)sender {
[self.myTableView setEditing:!self.myTableView.editing animated: YES];
[self.editButton setTitle:self.myTableView.editing ? NSLocalizedString(#"Done", nil) : NSLocalizedString(#"Edit", nil)];
}
I just add this methods in .h file :
- (IBAction)EditTable:(id)sender;
- (IBAction)DeleteButtonAction:(id)sender;
and in .m file :
(IBAction)DeleteButtonAction:(id)sender{
[tableList removeLastObject];
[Table reloadData];
}
(IBAction) EditTable:(id)sender{
if(self.editing)
{
[super setEditing:NO animated:NO];
[Table setEditing:NO animated:NO];
[Table reloadData];
[self.navigationItem.leftBarButtonItem setTitle:#"Edit"];
[self.navigationItem.leftBarButtonItem setStyle:UIBarButtonItemStylePlain];
}
else
{
[super setEditing:YES animated:YES];
[Table setEditing:YES animated:YES];
[Table reloadData];
[self.navigationItem.leftBarButtonItem setTitle:#"Done"];
[self.navigationItem.leftBarButtonItem setStyle:UIBarButtonItemStyleDone];
}
}
when I run the program and click the delete button (red button) the program is stop !
whats the problem ? please any help ?
you are evil :(
OK, again my code in .h file is :
- (IBAction)EditTable:(id)sender;
- (IBAction)DeleteButtonAction:(id)sender;
and in .m file is :
- (IBAction)DeleteButtonAction:(id)sender{
[tableList removeLastObject];
[Table reloadData];
}
- (IBAction) EditTable:(id)sender{
if(self.editing)
{
[super setEditing:NO animated:NO];
[Table setEditing:NO animated:NO];
[Table reloadData];
[self.navigationItem.leftBarButtonItem setTitle:#"Edit"];
[self.navigationItem.leftBarButtonItem setStyle:UIBarButtonItemStylePlain];
}
else
{
[super setEditing:YES animated:YES];
[Table setEditing:YES animated:YES];
[Table reloadData];
[self.navigationItem.leftBarButtonItem setTitle:#"Done"];
[self.navigationItem.leftBarButtonItem setStyle:UIBarButtonItemStyleDone];
} }
when I run the program and click the delete button (red button) the program is crash ! whats the problem ? please any help ?
If I am not wrong then you want to delete the cell of the tableView when delete button is clicked....
You need to call one other method of tableview:
//To Delete the Data
- (void)setEditing:(BOOL)editing animated:(BOOL)animated {
// Updates the appearance of the Edit|Done button as necessary.
[super setEditing:editing animated:animated];
[tblViewBM setEditing:editing animated:YES];
// Disable the add button while editing.
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:
(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
//Use your Array from which you need to delete the data.
NSMutableDictionary *dict=(NSMutableDictionary *)[appDel.BookMarkAry objectAtIndex:indexPath.row];
type=[dict valueForKey:#"type"];
[appDel.BookMarkAry removeObjectAtIndex:indexPath.row];
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
}
I am sure this will Definately help you to delete the cell with data from array also.
I have a tableview. I need to add cells of the tableview at a particular interval of time after loading so that we can view loading the cells.How can i do this. Any idea will be greatly appreciated!
Set up a timer in your viewDidLoad method of your UITableViewController like so:
- (void)viewDidLoad {
[super viewDidLoad];
// Schedule a timer to fire every 5 seconds and call our
// insertNewObject method
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:5
target:self
selector:#selector(insertNewObject)
userInfo:nil
repeats:YES];
}
Then insert a new row into our data source and tell the tableView about it
- (void)insertRow {
// dataSource defined elsewhere
[dataSource addObject:#"New row"];
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:([dataSource count] - 1) inSection:0];
NSArray *indexPaths = [NSArray arrayWithObject:indexPath];
[[self tableView] beginUpdates];
[[self tableView] insertRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationFade];
[[self tableView] endUpdates];
}
I've got a UITableView with several entries. Upon selecting one, I need it to do a potentially time-consuming network operation. To give the user some feedback, I tried to place a UIActivityIndicatorView in the UITableViewCell. However, the spinner doesn't appear until much later -- after I've done the expensive operation! What am I doing wrong?
- (NSIndexPath *) tableView:(UITableView *) tableView
willSelectRowAtIndexPath:(NSIndexPath *) indexPath {
UIActivityIndicatorView *spinner = [[UIActivityIndicatorView alloc]
initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];
[spinner autorelease];
[spinner startAnimating];
[[tableView cellForRowAtIndexPath:indexPath] setAccessoryView:activity];
if ([self lengthyNetworkRequest] == nil) {
// ...
return nil;
}
return indexPath;
}
As you can see, I have the spinner being set to the accessoryView before the lengthy network operation. But it only appears after the tableView:willSelectRowAtIndexPath: method finishes.
Once you tell the ActivityIndicator to start animating, you have to give your application's run loop a chance to start the animation before starting the long operation. This can be achieved by moving the expensive code into its own method and calling:
[self performSelector:#selector(longOperation) withObject:nil afterDelay:0];
EDIT: I think you should be using didSelect instead of willSelect.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
Try adding [CATransaction flush] right before
if ([self lengthyNetworkRequest] == nil) {
- (NSIndexPath *) tableView:(UITableView *) tableView
willSelectRowAtIndexPath:(NSIndexPath *) indexPath {
UIActivityIndicatorView *spinner = [[UIActivityIndicatorView alloc]
initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];
[spinner autorelease];
[spinner startAnimating];
[[tableView cellForRowAtIndexPath:indexPath] setAccessoryView:activity];
if ([self lengthyNetworkRequest] == nil) {
//doing the intensive work after a delay so the UI gets updated first
[self performSelector:#selector(methodThatTakesALongTime) withObject:nil afterDelay:0.25];
//you could also choose "performSelectorInBackground"
}
return indexPath;
}
- (void)methodthatTakesALongTime{
//do intensive work here, pass in indexpath if needed to update the spinner again
}