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
Related
I would like to number the rows in my app, just like in excel. I use a label for this in the cell. I have written some code which does this perfectly:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
cell.numberlabel.text = [NSString stringWithFormat:#"%li.",(indexPath.row+1)];
return cell;
}
However the problem is, that whenever I delete a row the numbering does not get refreshed. So I thought maybe I would iterate through every cell and set the number again, whenever the user deletes a row. Here is what I did:
NSArray *cells = [tableView visibleCells];
int n = 0;
for (TableViewCell *cell in cells)
{
n++;
cell.numberlabel.text = [NSString stringWithFormat:#"%i.",n];
}
This works great, but again I faced another problem: The tableview is reusing cells so I can not iterate through each and every one of them, only the ones that are actually on screen.
So my question is: How would I go about solving this issue of properly numbering each row in the TableView, even if the user starts deleting rows?
You have to do the following:
Use your first approach by setting the label text in the cellForRowAtIndexPath method
Delete your desired row
Now do not reload the whole tableview but use reloadRowsAtIndexPaths for all visible cells. All offscreen cells will have the correct row number as soon as they become visible because it will be set in the cellForRowAtIndexPath method.
Example:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Default" forIndexPath:indexPath];
cell.textLabel.text = [NSString stringWithFormat:#"%li", indexPath.row +1];
return cell;
}
- (NSArray *) tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewRowAction *deleteAction = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDefault title:#"Delete" handler:^(UITableViewRowAction *action, NSIndexPath *indexPath) {
self.numberOfRows--;
NSMutableArray *visibleCellIndexPaths = [[tableView indexPathsForVisibleRows] mutableCopy];
[visibleCellIndexPaths filterUsingPredicate:[NSPredicate predicateWithFormat:#"row > %i",indexPath.row]];
[tableView beginUpdates];
[tableView deleteRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationTop];
[tableView reloadRowsAtIndexPaths:visibleCellIndexPaths withRowAnimation:UITableViewRowAnimationFade];
[tableView endUpdates];
}];
return #[deleteAction];
}
i think first method be great
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
cell.numberlabel.text = [NSString stringWithFormat:#"%li.",(indexPath.row+1)];
return cell;
}
if user delete row, you simply can catch this and reload data and table view redraw with normal values
If you don't want to reload the table after the deletion,
then you can use the following approach:
You can iterate through the cells.
Iteration will start from the indexpath of the cell which recently got deleted to the number of rows.
And you can reduce their number by one during iteration.
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 have a UITableViewcell that stays highlighted after touching it. I would like to know how to remove the highlight right after it becomes visible after your touch.
So when you touch the UITableViewCell I would like it to become selected and highlighted then when the user raises their finger I would like to deselect and unhighlight the UITableViewCell.
This is what I am doing so far, and the deselect works but the cell is still highlighted.
#pragma mark -- select row
- (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(#"%#", indexPath);
NSLog(#"%#", cell.textLabel.text);
}
#pragma mark -- deselect row
-(void) tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
-(void) tableView:(UITableView *)tableView didDeselectRowAtIndexPath:
(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
That's an infinite loop, I'm quite certain. However... it's sort of on the right track. You can move that method call into didSelectRowAtIndexPath:.
- (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:
(NSIndexPath *)indexPath {
//stuff
//as last line:
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
For that matter, deselectRowAtIndexPath can be called from anywhere at any time you want the row to be deselected.
[self.myTableView deselectRowAtIndexPath:[self.myTableView
indexPathForSelectedRow] animated: YES];
You need to deselect row on didSelectRowAtIndexPath method
Example code
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:NO];
}
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.
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];