I implemented the body of the method moveRowAtIndexPath:toIndexPath: as follows:
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath
{
XYZToDoItem *itemToMove = [self.toDoItems objectAtIndex:fromIndexPath.row];
NSLog(#"Moving");
NSLog( itemToMove.itemName);
[self.toDoItems removeObjectAtIndex:fromIndexPath.row];
[self.toDoItems insertObject:itemToMove atIndex:toIndexPath.row];
}
I'd like to call this method from TableViewController's didSelectRowAtIndexPath method.
When I do the rows of the table do move, but the above method doesn't seem to execute. Nothing logs to the console and the items in the array toDoItems DO NOT swap.
Here's the body of that method:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSIndexPath *indexPathOfLastItem =
[NSIndexPath indexPathForRow:([self.toDoItems count] - 1) inSection:0];
[tableView moveRowAtIndexPath:indexPath toIndexPath:indexPathOfLastItem];
}
How do I get the table view to move rows properly from within the delegate (the TableViewController)?
Moving (or adding, removing) table view rows by code (and not by user interaction) does not cause the
data source methods to be called.
If you need the data source method to be executed, you need to call it explicitly:
// Move table view row:
[tableView moveRowAtIndexPath:indexPath toIndexPath:indexPathOfLastItem];
// Call data source method:
[self tableView:tableView moveRowAtIndexPath:indexPath toIndexPath:indexPathOfLastItem];
Swift 3:
// Move table view row:
tableView.moveRow(at: indexPath, to: indexPathOfLastItem)
// Call data source method:
self.tableView.moveRow(at: indexPath, to: indexPathOfLastItem)
I don't think you're calling the method correctly, since it's not a real delegate method you have to call it on self.
Try:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSIndexPath *indexPathOfLastItem =
[NSIndexPath indexPathForRow:([self.toDoItems count] - 1) inSection:0];
[self tableView:tableView moveRowAtIndexPath:indexPath toIndexPath:indexPathOfLastItem];
}
Related
A UITableView which have UITableViewCell of 20 rows, each row do have one button on it, click button I want to drop the UITableViewCell to bottom to UITableView.
Is there any delegate method which do for it.
Your feedback will be appreciated.
Yes, there is a method on tableview
- (void)moveRowAtIndexPath:(NSIndexPath*)indexPath
toIndexPath:(NSIndexPath*)newIndexPath
You can read more https://developer.apple.com/library/ios/documentation/UIKit/Reference/UITableView_Class/#//apple_ref/occ/instm/UITableView/moveRowAtIndexPath:toIndexPath:
Yes, there is one!
Use below delegate methods for that:
have to return YES to allow moving of tableView row in canMoveRowAtIndexPath delegate method as per your requirement,
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.row == 0) // Don't move the first row
return NO;
return YES;
}
Then, use moveRowAtIndexPath delegate method to Updating the data-model array for the relocated row accordingly,
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath
toIndexPath:(NSIndexPath *)toIndexPath
{
//Updating the data-model array
}
Like moveRowAtIndexPath in button click,
- (void)btnClick:(UIButton*)sender
{
UITableViewCell *cell = (UITableViewCell *)sender.superview;
NSIndexPath *indexpath = [tableView indexPathForCell:cell];
//Change accordindly as per requirement
[tableView moveRowAtIndexPath:[NSIndexPath indexPathForItem:indexpath.row inSection:indexpath.section] toIndexPath:[NSIndexPath indexPathForItem:0 inSection:indexpath.section]];
}
Also, read Apple documentation for same:
https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/TableView_iPhone/ManageReorderRow/ManageReorderRow.html
I have a custom UITableViewCell called CustomCell which has a UILabel in it which it is supposed to show the current index number + 1 (It is a queue of things to do).
I am using the setEditing method to allow the users to move cells around however I just cannot get the cells to be numbered correctly (in order) with the following code. Basically I am just trying to access the cells in the region the method parameters are passed but the numbers are simply returning out of order. What am I doing wrong here?
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath {
[queuedToDoArray moveObjectAtIndex:fromIndexPath.row toIndex:toIndexPath.row];
NSIndexPath *lowerIndexPath = (fromIndexPath.row < toIndexPath.row ? fromIndexPath : toIndexPath);
NSIndexPath *higherIndexPath = (fromIndexPath.row > toIndexPath.row ? fromIndexPath : toIndexPath);
//Update all the queue numbers in between moved indexes
for (int i = lowerIndexPath.row; i <= higherIndexPath.row; i++) {
NSIndexPath *currentIndexPath = [NSIndexPath indexPathForRow:i inSection:0];
CustomCell *currentCell = [todoTable cellForRowAtIndexPath:currentIndexPath];
[currentCell.queueNumber setText:[NSString stringWithFormat:#"%i", currentIndexPath.row + 1]];
}
}
You should not configure your tableview cell a.k.a customCell in moveRowAtIndexPath method, instead, just updating the data-model array for the relocated row.
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath {
NSString *stringToMove = [self.queuedToDoArray objectAtIndex:sourceIndexPath.row];
[self.queuedToDoArray removeObjectAtIndex:sourceIndexPath.row];
[self.queuedToDoArray insertObject:stringToMove atIndex:destinationIndexPath.row];
}
After that, just call [self.tableView reloadData] and it will automatically do that for you.
Please check out the Apple Developer Document for more details.
Edit:
A better solution is just reloading the relative sections or rows as #Paulw11 commented.
In didSelectRowAtIndexPath method of my Table View Controller for some reasons i should call reloadData of my Table View. After this any selection will disappear. Which is proper way to preserve selection of table?
UPD: i tried to do selectRowAtIndexPath after i reload table in didSelectRowAtIndexPath, but it didn't lead to any result, selection is still missing. But it will work if i will do it in dispatch_after block, although it's a very strange solution. I need to do it in a right way.
Add -selectRowAtIndexPath with animated flag set to NO after you call [tableView reloadData] inside -didSelectRowAtIndexPath.
Objective-C:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
...
[tableView reloadData];
[tableView selectRowAtIndexPath:indexPath animated:NO scrollPosition:UITableViewScrollPositionNone];
...
}
Swift:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
...
tableView.reloadData()
tableView.selectRowAtIndexPath(indexPath, animated: false, scrollPosition: .None)
...
}
You can use.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:YES];
//add you code and reload the table
}
The reload happens during the next layout pass, which normally happens when you return control to the run loop (after, say, your button action or whatever returns).
So one way to run something after the table view reloads is simply to force the table view to perform layout immediately:
- (void)reloadTableView
{
NSArray *indexPaths = [self.tableView indexPathsForSelectedRows];
[self.tableView reloadData];
[self.tableView layoutIfNeeded];
for (NSIndexPath *path in indexPaths) {
[self.tableView selectRowAtIndexPath:path animated:NO scrollPosition:UITableViewScrollPositionNone];
}
}
Or as you said you can use GCD to schedule your after-layout code to run later
- (void)reloadTableView
{
NSArray *indexPaths = [self.tableView indexPathsForSelectedRows];
[self.tableView reloadData];
dispatch_async(dispatch_get_main_queue(), ^{
for (NSIndexPath *path in indexPaths) {
[self.tableView selectRowAtIndexPath:path animated:NO scrollPosition:UITableViewScrollPositionNone];
}
}
}
In "didSelectRowAtIndexPath" delegate method, keep a reference of your selected indexPath:
indexPathReference = indexPath;
And after reloading the table view add this line:
[tableView selectRowAtIndexPath:indexPathReference animated:NO scrollPosition:UITableViewScrollPositionNone];
In didSelectRowAtIndexPath you must keep a reference to the selected indexPath.
Then you should call reloadData
reloadData will trigger calls to cellForRowAtIndexPath:
That's where you check each index with your stored indexPath and set the cell as selected. (cell.selected = true)
Here are tableView data source and delegate implementation, and I set the maximum selection is 5.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
...
if ([multiOptions count] > 5) {
[self tableView:tableView didDeselectRowAtIndexPath:indexPath];
cell.accessoryType = UITableViewCellAccessoryNone;
cell.selected = NO;
//show alert
}
...
}
- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath
{
...
[multiOptions removeObject:selectedOption];
...
}
but here comes a question, if the options exceed the limit, the first click on cell will work just fine. but second time click the cell will call
didDeselectRowAtIndexPath
again, that's not what i expected, and I tried
[tableView deselectRowAtIndexPath:indexPath animated:YES];
in didSelectRowAtIndexPath, it didn't work, can someone give me a hint, how to correct it? thanks.
You have to check this in tableView:willSelectRowAtIndexPath:
Have a look at the UITableView class reference
especially at the last sentence:
Return Value An index-path object that confirms or alters the selected
row. Return an NSIndexPath object other than indexPath if you want
another cell to be selected. Return nil if you don't want the row
selected.
So something like this will work within tableView:willSelectRowAtIndexPath::
if ([multiOptions count] > 5) return nil;
I have a "UITableView", I am trying to handle selected row and use its data accordingly,
I have written necessary code to take the selected row, unfortunately it seems it does not work
If i select nothing,
NSIndexPath *path = [tableViewDoctorName indexPathForSelectedRow];
int rowSelected = path.row;
rowSelected's value is 0;
But, when i select the row it is again 0.
I have only one row in a table, i am not sure does it matter?
How can i accurately determine the selected row in a "UITableView"?
Set the UITableView delegate and implement this method:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
int rowSelected = indexPath.row;
}
indexPath.row start with 0 for first row, And you have only one row then it return always 0;
But if you want to get data of selected Row then you delegate method of UITableView.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// here you can get directly indexPath.row so you can get required data;
}
Of course how many rows you have in your tableView matters : if you only have 1, then its indexpath is (0 ,0) and this is the only one that can be (selected) in this case.
The selected row generally is highlighted (in blue) so you might want to store it in another property of your tableView delegate, if you don't want this blue selection to stay on-screen.
Typically, in your UITableViewDelegate :
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// deselect the row, to avoid the 'blue' selection to stay on-screen
[tableView deselectRowAtIndexPath:indexPath animated:YES];
// save your own copy of 'last' selected indexPath
self.mySavedIndexPath = indexPath;
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
_selectedIndexPath = indexPath;
}
In outside the function,
use this to get selected row,
NSIndexPath *indexPath = [NSIndexPath indexPathForRow: _selectedIndexPath.row inSection:0];
int rowSelected = indexPath.row;