Can someone tell me how to move a row in UITableView automatically when selected.
To be more clearer my tableview has a number of items. When the users selects a row that row has to be moved to the bottom most row in UITableView.
Any code snippets or pointers would be appreciated.
Thanks
Use a method from UITableViewDelegate protocol
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSUInteger index = indexPath.row;
NSUInteger lastIndex = tableDataArray.count - 1;
if (index == lastIndex) {
return;
}
id obj = [[tableDataArray objectAtIndex:index] retain];
[tableDataArray removeObjectAtIndex:index];
[tableDataArray addObject:obj];
[obj release];
//// without animation
[tableView reloadData];
//// with animation
// [tableView beginUpdates];
// [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationBottom];
// [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:lastIndex inSection:0]] withRowAnimation:UITableViewRowAnimationTop];
// [tableView endUpdates];
}
You can use the table view delegate methods to perform this.
To obtain the selected row u can use
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
This will help you to get an idea on moving rows.
http://developer.apple.com/library/ios/#documentation/userexperience/conceptual/TableView_iPhone/ManageReorderRow/ManageReorderRow.html
when the row is selected modify your datasouce ,may be your array and reload table view.
ie
in your
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
get you indexpath and remove that data from your datasource array and place that value in your last of your data source array and finally reload tableview using
[tableview reloadData];
Related
I am having one number of section base tableview in that plus button which will add new item in tableview.
While i try add or delete the section from tableview and reload that tableview it will blink old record many times and then add or delete the section. Here is the code.
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
SymbolTableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
if ([selectIndexPath containsObject:[NSNumber numberWithInt:(int)indexPath.section]])
{
[selectSymbol removeObject:cell.lblsymbol.text];
[selectIndexPath removeObject:[NSNumber numberWithInt:(int)indexPath.section]];
}
else
{
NSString *strr = cell.lblsymbol.text;
[selectSymbol addObject:strr];
[selectIndexPath addObject:[NSNumber numberWithInt:(int)indexPath.section]];
}
[tblDetail reloadData];
}
what is the issue?
try following code it may helps you
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath: (NSIndexPath *)indexPath
{
SymbolTableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
if ([selectIndexPath containsObject:[NSNumber numberWithInt:(int)indexPath.section]])
{
[tblDetail beginUpdates];
[selectSymbol removeObject:cell.lblsymbol.text];
[selectIndexPath removeObject:[NSNumber numberWithInt:(int)indexPath.section]];
[tableView deleteRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationFade];
[tableView endUpdates];
}
else
{
NSString *strr = cell.lblsymbol.text;
[tblDetail beginUpdates];
[selectSymbol addObject:strr];
[selectIndexPath addObject:[NSNumber numberWithInt:(int)indexPath.section]];
[tableView reloadRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationFade];
[tableView endUpdates];
}
}
You can reload cell which you removed/added
You will not reload all table.
Try the following code please
[self.tableView deleteRowsAtIndexPaths:#[ indexPath ] withRowAnimation:UITableViewRowAnimationFade];
or
[self.tableView insertRowsAtIndexPaths:#[ indexPath ] withRowAnimation:UITableViewRowAnimationFade];
for inserting row in tableview
- (void)insertNewObject:(id)sender
{
if (!arrayForTableContent) {
arrayForTableContent = [[NSMutableArray alloc] init];
}
NSInteger count = [arrayForTableContent count];
NSString *strTobeAdded = [NSString stringWithFormat:#"%d",count+1];
[arrayForTableContent insertObject:strTobeAdded atIndex:count];
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:count inSection:0];
[self.tableViewForScreen insertRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
}
I'm not writing all the code nor test it in the debugger, but I will give you an advice of how to proper implement this. Let's say you have a datasource, like this:
NSMutableArray *data = #[#"First", #"Second", #"Third"];
Datasource: In numberOfRowsInSection, you return data.count; in cellForRowAtIndexPath, you will configure the cell with the respective index from the array;
Delegate: In didSelectRowAtIndexPath, remove the object from the data array, say you will need something like this: [data removeObjectAtIndex(indexPath.row)]; then call reloadData on the table view. The table view will smoothly return now just two items.
I have a static tableview that shows a date picker when the appropriate cell is selected. The didSelectRowAtIndexPath triggers the show/hide of the date picker cell; however, it's not until the second selection that scrollToRow is executed and the picker cell is hidden.
-(void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell* cell = [tableView cellForRowAtIndexPath:indexPath];
[tableView beginUpdates];
if (cell == self.dateCell){
self.dateOpen = !self.isdateOpen;
[self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:3 inSection:1] atScrollPosition:UITableViewScrollPositionTop animated:YES];
}
[self.tableView reloadData];
[self.tableView endUpdates];
}
Any Ideas of where I've gone astray??
Thank You!!
EDIT: I forgot to add, it's the last row that's expanding with the date cell... I'm wondering how that would affect it. Although, I did just copy/paste a few cells to make it not the last row and it didn't help.
I've been reading a lot about updating a UITableView after you remove rows by both IndexPath and the datasource, which it seems like comes down to [tableView startUpdates], run whatever update code you have, then [tableView endUpdates].
Despite following numerous examples to a T, and utilizing [tableView deleteRowsAtIndexPaths:<indexPaths> withRowAnimation:UITableViewRowAnimationTop];
, I can't seem to make my rows delete in any way but what the following depicts:
http://www.youtube.com/watch?v=l6ov1FR0R4g&feature=youtu.be (essentially, if there are n > 1 rows, the row will simply blink out, and if there is n = 1 row, it will slide outward, stop, then disappear).
I'd really like a smoother behavior, like, perhaps, the row slides out, as the row slides up. Here's the code executing the deletion:
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
int idx = [indexPath indexAtPosition:1];
LoLoanedItemDoc *itemDoc = [[self items] objectAtIndex:idx];
// Delete notification
[[UIApplication sharedApplication] cancelLocalNotification:[[itemDoc data] notification]];
[tableView beginUpdates];
[tableView deleteRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationTop];
// Remove from datasource
[[self items] removeObject:itemDoc];
[tableView endUpdates];
// Delete folder
[itemDoc deleteDoc];
}
I've done it two ways, both of which work for me.
Delete the item before you perform the updates.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete) {
//Delete the item from the data source
[self removeProductFromQuoteAtIndexPath:indexPath];
//Do the updates
[tableView beginUpdates];
[tableView deleteRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationFade];
[tableView endUpdates];
}
}
// Override to support editing the table view.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete) {
[shipping removeObjectAtIndex:indexPath.row - 1];
[tableView deleteRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
}
Are you performing any type of operation on the cell before it deletes? (like closing the drawer animation you have).
I want to copy a row to another section when a button in the row is tapped.i have done it.But only the text is getting copied.I also want to move the image which is in that row.
-(void)moveRowToAnotherSection:(id)sender{
UIButton *button = (UIButton *)sender;
UITableViewCell *cell = (UITableViewCell *)button.superview;
NSMutableArray *tempArr = [[NSMutableArray alloc] init];
[[self tableView] beginUpdates];
[tempArr addObject:[NSIndexPath indexPathForRow:self.favouritesArray.count inSection:0]];
[self.favouritesArray insertObject:cell.textLabel.text atIndex:self.favouritesArray.count];
[[self tableView] insertRowsAtIndexPaths:(NSArray *)tempArr withRowAnimation:UITableViewRowAnimationFade];
[[self tableView] endUpdates];
}
There are three points I want to make:
1) You want to move the image when a particular row is tapped, right?
Then why dont you use Tableview delegate's method- didSelectRowAtIndexPath.
2) There is a method in UITableView that is used to move rows. Here is from the Apple Documentation:
- (void)moveRowAtIndexPath:(NSIndexPath *)indexPath toIndexPath:(NSIndexPath *)newIndexPath
Moves the row at a specified location to a destination location.
Here is the piece of code that moves the tapped row to section 0 row 0.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
NSIndexPath *path = [NSIndexPath indexPathForRow:0 inSection:0];
[tableView beginUpdates];
[tableView moveRowAtIndexPath:path toIndexPath:indexPath];
[tableView moveRowAtIndexPath:indexPath toIndexPath:path];
[tableView endUpdates];
}
3) The third point is the main one. UITableView by default provides a reordering control and if you want to reorder rows by dragging and not tapping, you can achieve this following these steps:
Step 1:
Set your tableview to editing mode. Normally this is done through an Edit Button.
[_yourTableView setEditing:YES animated:YES];
Step 2:
In - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
assign
cell.showsReorderControl = YES;
Step 3:
Implement UITableViewDataSource's method
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath{
// here you do all the reordering in your dataSource Array. Because dragging rows change the index of your row but the change should reflect in yopur array as well.
}
Thats it, you don't need to write any code under beginUpdates and endUpdates block. You just have to implement these three steps.
Read this to learn all about Reordering in TableView
Note: when I tap the row, then the app crashes.
I'm trying to implement adding a new cell on a user's tap. I found that there was a similar example in WWDC 2011's table view demonstration. Here's my code from my table view.
Here is the error:
2013-03-19 20:04:28.672 Project[51229:c07] *** Assertion failure in -[UITableView _endCellAnimationsWithContext:], /SourceCache/UIKit_Sim/UIKit-2380.17/UITableView.m:1070
Here is my code from the table view.
#interface MyPFQueryTableViewController : PFQueryTableViewController <PFLogInViewControllerDelegate, PFSignUpViewControllerDelegate>
#property (nonatomic, strong) NSIndexPath *controlRowIndexPath;
#property (nonatomic, strong) NSIndexPath *tappedIndexPath;
#implementation MyPFQueryTableViewController {
ListItemObject *listDetail;
}
#synthesize controlRowIndexPath;
#synthesize tappedIndexPath;
-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
PFObject *object = [self.objects objectAtIndex:indexPath.row];
[object deleteInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
[self loadObjects];
}];
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath object:(PFObject *)object {
static NSString *CellIdentifier = #"listCell";
PFTableViewCell *cell = (PFTableViewCell *)[tableView dequeueReusableCellWithIdentifier:#"listCell"];
if (cell == nil) {
cell = [[PFTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// Configure the cell
cell.textLabel.text = [object objectForKey:self.textKey];
//cell.imageView.file = [object objectForKey:self.imageKey];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[super tableView:tableView didSelectRowAtIndexPath:indexPath];
//if user tapped the same row twice let's start getting rid of the control cell
if([indexPath isEqual:self.tappedIndexPath]){
[tableView deselectRowAtIndexPath:indexPath animated:NO];
}
//update the indexpath if needed... I explain this below
indexPath = [self modelIndexPathforIndexPath:indexPath];
//pointer to delete the control cell
NSIndexPath *indexPathToDelete = self.controlRowIndexPath;
//if in fact I tapped the same row twice lets clear our tapping trackers
if([indexPath isEqual:self.tappedIndexPath]){
self.tappedIndexPath = nil;
self.controlRowIndexPath = nil;
}
//otherwise let's update them appropriately
else{
self.tappedIndexPath = indexPath; //the row the user just tapped.
//Now I set the location of where I need to add the dummy cell
self.controlRowIndexPath = [NSIndexPath indexPathForRow:indexPath.row + 1 inSection:indexPath.section];
}
//all logic is done, lets start updating the table
[tableView beginUpdates];
//lets delete the control cell, either the user tapped the same row twice or tapped another row
if(indexPathToDelete){
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPathToDelete]
withRowAnimation:UITableViewRowAnimationNone];
}
//lets add the new control cell in the right place
if(self.controlRowIndexPath){
[self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:self.controlRowIndexPath]
withRowAnimation:UITableViewRowAnimationNone];
}
//and we are done...
[tableView endUpdates];
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if([indexPath isEqual:self.controlRowIndexPath]){
return 45; //height for control cell
}
return 70; //height for every other cell
}
- (NSIndexPath *)modelIndexPathforIndexPath:(NSIndexPath *)indexPath
{
int whereIsTheControlRow = self.controlRowIndexPath.row;
if(self.controlRowIndexPath != nil && indexPath.row > whereIsTheControlRow)
return [NSIndexPath indexPathForRow:indexPath.row - 1 inSection:0];
return indexPath;
}
#end
The problem is in your didSelectRowAtIndexPath method. You have:
[tableView beginUpdates];
//lets delete the control cell, either the user tapped the same row twice or tapped another row
if(indexPathToDelete){
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPathToDelete]
withRowAnimation:UITableViewRowAnimationNone];
}
//lets add the new control cell in the right place
if(self.controlRowIndexPath){
[self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:self.controlRowIndexPath]
withRowAnimation:UITableViewRowAnimationNone];
}
//and we are done...
[tableView endUpdates];
Before you make any calls to tell the table to add or remove any rows, you must update your data source with by adding or removing data. The table will check how many sections and rows there are before and after your add/remove rows. The number of sections and rows after the change must properly reflect how much data you add/remove with how many rows you add/remove.
And of course you must implement the numberOfRowsInSection method.
What does your - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section look like?
This error happens when you try to add or delete a row from the UITableView, but the number of rows that you claim to be in the section after the update in that method is not consistent with the new data that should be loaded.
Ex, if your numberOfRowsInSection always returns 4 and you add a row in that section, the tableView will want it to be 5, but it will not be so it will crash. You need to keep track of how many rows are in each section and return that number.