I have a UITableView in my Objective-C iOS app, of which I need to have a specific cell displaying information while all the others cells should move freely.
With my current code, I prevented said cell to be moved by other cells, but it is still possible to move underneath it.
This cell is not part of my Data model so I really need to keep this in the controller layer.
In other words, I'm looking for a way to prevent the default behaviour.
Below is my current code:
-(void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath
{
if (destinationIndexPath.row == [tableView numberOfRowsInSection:0]-2) {
//prevent the move
}
else {
[[BNRItemStore sharedStore] moveItemAtIndex:sourceIndexPath.row toIndex:destinationIndexPath.row];
}
}
What should I change in order to obtain the desired functionality?
Did you try to implement this delegate method?
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath;
Use targetIndexPathForMoveFromRowAtIndexPath as below,
// Allows customization of the target row for a particular row as it is being moved/reordered
- (NSIndexPath *)tableView:(UITableView *)tableView targetIndexPathForMoveFromRowAtIndexPath:(NSIndexPath *)sourceIndexPath toProposedIndexPath:(NSIndexPath *)proposedDestinationIndexPath {
if( proposedDestinationIndexPath is ok ) {
return proposedDestinationIndexPath;
} else {
return sourceIndexPath;
}
}
Related
I need to keep my first cell always located at top of tableview when i move others cell.I spent a lot of time and many ways button i haven't figure out that how to solve this problem.
This is my code:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//...do something to custom first cell design from xib file
//...do some thing to custom normal cells(cells at below of first cell)
[firstcell setEditing:NO animated:YES];
firstcell.userInteractionEnabled=NO;
if (indexPath.row==0)
{
return firstcell;
}
else
{
return cell;
}
}
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.row == 0) // Don't move the first row
return NO;
return YES;
}
-(BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
return YES;
}
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath {
// i just change datasource for tableview at here
}
And there is my tableview when I move cell (normal cell).
I wanna keep first cell (blue cell) always be at top and not be interact by others cell.
You need to implement one more delegate method:
- (NSIndexPath *)tableView:(UITableView *)tableView targetIndexPathForMoveFromRowAtIndexPath:(NSIndexPath *)sourceIndexPath toProposedIndexPath:(NSIndexPath *)proposedDestinationIndexPath {
if (proposedDestinationIndexPath.row == 0) {
// Don't allow a row to be moved to the first row position
return [NSIndexPath indexPathForRow:1 inSection:0];
} else {
return proposedDestinationIndexPath;
}
}
This code assume you only have one section in your table view.
The point of this method is to tell the table view that if the proposed destination for the row being moved isn't appropriate, the returned value should be used. As written here, any attempt to move a row to the top will result in it being moved just below the top row.
I tried to implement this method in order to be able to move the cells in my Tableview.
And everything runs well but the bars aren't shown and I'm not able to move the cells.
- (void)moveRowAtIndexPath:(NSIndexPath *)indexPath toIndexPath:(NSIndexPath *)newIndexPath {
[[HPPossessionStore defaultStore] movePossessionAtIndex:[indexPath row] toIndex:[newIndexPath row]];
}
What do I have to do to make it work?
Add below delegate method as well.
- (BOOL)tableView:(UITableView *)tableView
canMoveRowAtIndexPath:(NSIndexPath *)indexPath {
return YES;
}
This solved my problem, although I have no idea why. If someone could explain it I would be very thankful.
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath
{
[[HPPossessionStore defaultStore] movePossessionAtIndex:[fromIndexPath row] toIndex:[toIndexPath row]];
}
It is explained in more detail here: https://stackoverflow.com/a/20786785/2310837
I want to implement a method to be able to reorder the rows of a tableview.
In each section i only have one row. When the editing-state of the tableview is enabled, the move indicators appear as expacted. But when i drag one of the cell to another position, the cell immediatly (after approximatly 1 s) pops back to the original position. This is weired to me, because i implemented such a reorder functionality already. The difference between those two projects are that the new project implements a bunch of gesture recognizers (eg UILongPressGestureRecognizer, UIPanGestureRecognizer, UIPinchGestureRecognizer,..). I already thought about the possibility that one of the gesture recognizers is blocking the drag action of the tableviewcell but its not.
You can see the code below:
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath {
return YES;
}
- (NSIndexPath *)tableView:(UITableView *)tableView targetIndexPathForMoveFromRowAtIndexPath:(NSIndexPath *)sourceIndexPath toProposedIndexPath:(NSIndexPath *)proposedDestinationIndexPath {
//return [NSIndexPath indexPathForRow:0 inSection:3];
return nil;
}
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath {
NSLog(#"%#", destinationIndexPath);
}
Can anyone help me pls?
UPDATE:
I found out that the moved tableviewcell is beeing moved to the original destination index path. Does that indicate, that a reloadData on the table view has happened?
2nd UPDATE:
Because it was menthioned by Andrei Shender why i return nil in the tableView:targetIndexPathForMoveFromRowAtIndexPath:toProposedIndexPath: method you can find my updated code below.
- (NSIndexPath *)tableView:(UITableView *)tableView targetIndexPathForMoveFromRowAtIndexPath:(NSIndexPath *)sourceIndexPath toProposedIndexPath:(NSIndexPath *)proposedDestinationIndexPath {
return proposedDestinationIndexPath;
//for testing purpose only
//return nil;
}
Btw when changing my code, i found out, that this method never gets called. Regarding to Apples documents about reordering tableviewcells it should get called.
Thanks to this posting I figured out, what the problem was. Combining a UIPanGestureRecognizer and a UITableView with the reorder/move funcationality is a tricky thing.
When i edit the tableview, i remove the gesture recognizer (of the viewcontroller's view) and when the editing is disabled again, i add the gesture recognizer again.
Be sure to update your data source in the method :
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath
I have a table. When I swipe horizontally across a table cell a button appears asking if I want to delete the row.
I do not want that feature. However, I looked up the code up and down and I never see where does this feature is implemented.
Other rows on other tables do not behave the same way.
I think what you want to do is:
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
// Return NO if you do not want the specified item to be editable.
return NO;
}
in your table's viewController.
However, I looked up the code up and down and I never see where does this feature is implemented.
It's implemented by the table view. You can prevent cells from being edited at all by returning NO from your table data source's implementation of -tableView:canEditRowAtIndexPath:, and you can change what editing options are available for a given row by returning an appropriate value from -tableView:editingStyleForRowAtIndexPath:.
- (UITableViewCellEditingStyle)tableView:(UITableView *)aTableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath {
// Detemine if it's in editing mode
if (self.editing) {
return UITableViewCellEditingStyleDelete;
}
return UITableViewCellEditingStyleNone;
}
or
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
return NO;
}
I have a table view with custom cells. The cells are filled with my data.
Now I want to enable the user to rearrange the rows. I have implemented the methods, but while dragging to reorder the cell, I can see it shows like it is trying to do but cannot move anywhere. It moves like 10 pixel as if it will do the rearrange but goes back to its position. How to reorder the rows with custom cell?
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete)
{
[self.dataSource removeObjectAtIndex:indexPath.row];
[tableView reloadData];
}
}
-(UITableViewCellEditingStyle)tableView:(UITableView*)tableView editingStyleForRowAtIndexPath:(NSIndexPath*)indexPath
{
if (self.mytableView.editing)
{
return UITableViewCellEditingStyleDelete;
}
return UITableViewCellEditingStyleNone;
}
-(BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
return YES;
}
-(BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
{
return YES;
}
-(void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath
{
id stringToMove = [self.dataSource objectAtIndex:sourceIndexPath.row];
[self.dataSource removeObjectAtIndex:sourceIndexPath.row];
[self.dataSource insertObject:stringToMove atIndex:destinationIndexPath.row];
}
-(NSIndexPath *)tableView:(UITableView *)tableView targetIndexPathForMoveFromRowAtIndexPath:(NSIndexPath *)sourceIndexPath toProposedIndexPath:(NSIndexPath *)proposedDestinationIndexPath
{
if (proposedDestinationIndexPath.section != sourceIndexPath.section)
{
return sourceIndexPath;
}
return proposedDestinationIndexPath;
}
I know this is old but I will still answer it. The issue here is with your tableView: targetIndexPathForMoveFromRowAtIndexPath: toProposedIndexPath: method (your last method)
Your logic is preventing any moving from happening. Your if-statement:
if (proposedDestinationIndexPath.section != sourceIndexPath.section)
is saying if the desired location (the location the user wants to bring the cell) is not my current location, then return my current location (so do not move the cell). Otherwise, if my desired location (the new location I want to go) is my current location then return the desired location (which is actually my current location).
I hope that makes sense, so basically you are saying that no matter what, make sure every cell always remains in its current location. To fix this, either remove this method (this is not needed unless there are moves that are illegal) or switch your two return statements, so:
-(NSIndexPath *)tableView:(UITableView *)tableView
targetIndexPathForMoveFromRowAtIndexPath:(NSIndexPath *)sourceIndexPath
toProposedIndexPath:(NSIndexPath *)proposedDestinationIndexPath {
if (proposedDestinationIndexPath.section != sourceIndexPath.section) {
return proposedDestinationIndexPath;
}
return sourceIndexPath;
}
In fact, the only method required to allow re-arranging is: tableView: moveRowAtIndexPath: toIndexPath:. So again, unless you want specific behavior out of the other methods you can save some code and just remove most of them (especially since in this situation you are mainly just implementing the defaults).