Reputation: 920
In my UITable view, i want to be able to switch the positions of two cells when you drag one on to the other. I have already completed this task. The only problem is that when you try to drag one over the other, all the rows that follow shift down to make room for the new one. I do not want this, I want the cells to essentially stay visually static when you are dragging the first cell around. Any ideas?
Thanks, Mitch
Upvotes: 1
Views: 1255
Reputation: 17094
This may be helpful, you can respond however you like to the delegate calls to achieve this effect:
https://github.com/alfiehanssen/AMHEditableTableView
Let me know if you have any questions,
Upvotes: 0
Reputation: 104082
I think you can do this with some trickery, which is after all, how Apple does a lot of its animations.
Start with a UIViewController with a table view as a subview
Add a pan gesture recognizer to the main view (you'll have to implement shouldRecognizeSimultaneouslyWithGestureRecognizer: and return YES, so it will work with the table view's own gesture recognizers)
When you start to drag, create a snapshot view of the cell you started the drag over, and add it as a subview of the main view. You'll probably want to disable the table view's scrolling at this point also.
Drag that snapshot view using the pan gesture recognizer's translationInView property
When you drop the view, delete the snapshot view, and update the table's data source to show the data in the new order you created with the move.
I haven't tried all of this yet (but I've used some elements of it in other projects), but I think this should give you a start on what you're trying to achieve. There are some more details to work out for sure -- what do you want to see in the spot from where you dragged the cell? A blank space? What do you want to see when the dragged view is dropped?
After Edit:
This is what I have so far, and it works pretty well. In the storyboard, I have a UITableViewController with two cell prototypes, both basic types. The one whose identifier is "Blank" just has no text in its label. The tableviewController is embedded in a navigation controller, and I've added a button to the navigation bar with the initial title of "Drag" -- this button is connected to the toggleDragging method.
@interface TableController ()
@property (strong,nonatomic) NSMutableArray *theData;
@property (strong,nonatomic) UIPanGestureRecognizer *panner;
@property (strong,nonatomic) UIView *cellSnapshotView;
@property (strong,nonatomic) NSIndexPath *draggingCellIndexPath;
@end
@implementation TableController
- (void)viewDidLoad {
[super viewDidLoad];
self.panner = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(moveCellImage:)];
[self.tableView addGestureRecognizer:self.panner];
self.panner.enabled = NO;
self.panner.delegate = self;
self.draggingCellIndexPath = [NSIndexPath indexPathForRow:-1 inSection:0];
self.theData = [@[@"One",@"Two",@"Three",@"Four",@"Five",@"Six",@"Seven",@"Eight",@"Nine",@"Black",@"Brown",@"Red",@"Orange",@"Yellow",@"Green",@"Blue",@"Violet",@"Gray",@"White"] mutableCopy];
}
-(IBAction)toggleDragging:(UIBarButtonItem *)sender {
if ([sender.title isEqualToString:@"Drag"]) {
self.panner.enabled = YES;
sender.title = @"Scroll";
}else{
self.panner.enabled = NO;
sender.title = @"Drag";
self.tableView.scrollEnabled = YES;
}
}
-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
return YES;
}
-(IBAction)moveCellImage:(UIPanGestureRecognizer *)panner {
if (! self.cellSnapshotView) {
CGPoint loc = [panner locationInView:self.tableView];
self.draggingCellIndexPath = [self.tableView indexPathForRowAtPoint:loc];
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:self.draggingCellIndexPath];
self.cellSnapshotView = [cell snapshotViewAfterScreenUpdates:YES];
self.cellSnapshotView.alpha = 0.8;
self.cellSnapshotView.layer.borderColor = [UIColor redColor].CGColor;
self.cellSnapshotView.layer.borderWidth = 1;
self.cellSnapshotView.frame = cell.frame;
[self.tableView addSubview:self.cellSnapshotView];
self.tableView.scrollEnabled = NO;
[self.tableView reloadRowsAtIndexPaths:@[self.draggingCellIndexPath] withRowAnimation:UITableViewRowAnimationNone]; // replace the cell with a blank one until the drag is over
}
CGPoint translation = [panner translationInView:self.view];
CGPoint cvCenter = self.cellSnapshotView.center;
cvCenter.x += translation.x;
cvCenter.y += translation.y;
self.cellSnapshotView.center = cvCenter;
[panner setTranslation:CGPointZero inView:self.view];
if (panner.state == UIGestureRecognizerStateEnded) {
UITableViewCell *droppedOnCell;
CGRect largestRect = CGRectZero;
for (UITableViewCell *cell in self.tableView.visibleCells) {
CGRect intersection = CGRectIntersection(cell.frame, self.cellSnapshotView.frame);
if (intersection.size.width * intersection.size.height >= largestRect.size.width * largestRect.size.height) {
largestRect = intersection;
droppedOnCell = cell;
}
}
NSIndexPath *droppedOnCellIndexPath = [self.tableView indexPathForCell:droppedOnCell];
[UIView animateWithDuration:.2 animations:^{
self.cellSnapshotView.center = droppedOnCell.center;
} completion:^(BOOL finished) {
[self.cellSnapshotView removeFromSuperview];
self.cellSnapshotView = nil;
NSIndexPath *savedDraggingCellIndexPath = self.draggingCellIndexPath;
if (![self.draggingCellIndexPath isEqual:droppedOnCellIndexPath]) {
self.draggingCellIndexPath = [NSIndexPath indexPathForRow:-1 inSection:0];
[self.theData exchangeObjectAtIndex:savedDraggingCellIndexPath.row withObjectAtIndex:droppedOnCellIndexPath.row];
[self.tableView reloadRowsAtIndexPaths:@[savedDraggingCellIndexPath, droppedOnCellIndexPath] withRowAnimation:UITableViewRowAnimationFade];
}else{
self.draggingCellIndexPath = [NSIndexPath indexPathForRow:-1 inSection:0];
[self.tableView reloadRowsAtIndexPaths:@[savedDraggingCellIndexPath] withRowAnimation:UITableViewRowAnimationNone];
}
}];
}
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return self.theData.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if ([self.draggingCellIndexPath isEqual:indexPath]) {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Blank" forIndexPath:indexPath];
return cell;
}
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath];
cell.textLabel.text = self.theData[indexPath.row];
return cell;
}
Upvotes: 1