利用长按手势移动TableView中的Cell


需要什么?

        UILongGestureRecognizer

        UITableView(可以用UICollectionView代替)

        UITableViewController(可以用UIViewController 或 UICollectionViewController)


首先给 table view 添加一个 UILongGestureRecognizer。可以在 table view controller 的 viewDidLoad 方法中添加。

UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc]
  initWithTarget:self action:@selector(longPressGestureRecognized:)];
[self.tableView addGestureRecognizer:longPress];


为 gesture recognizer 添加 action 方法。该方法首先应该获取到在 table view 中长按的位置,然后找出这个位置对应的 cell 的 index。记住:这里获取到的 index path 有可能为 nil(例如,如果用户长按在 table view的section header上)。

- (IBAction)longPressGestureRecognized:(id)sender {
 
  UILongPressGestureRecognizer *longPress = (UILongPressGestureRecognizer *)sender;
  UIGestureRecognizerState state = longPress.state;
 
  CGPoint location = [longPress locationInView:self.tableView];
  NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:location];
 
  // More coming soon...
}

接着你需要处理UIGestureRecognizerStateBegan分支。如果获取到一个有效的 index path(non-nil),就去获取对应的UITableViewCell,并利用一个 helper 方法获取这个 table view cell 的 snapshot view。然后将这个 snapshot view 添加到 table view 中,并将其 center 到对应的 cell上。

为了更好的用户体验,以及更自然的效果,在这里我把原始 cell 的背景设置为黑色,并给 snapshot view 增加淡入效果,让 snapshot view 比 原始 cell 稍微大一点,将它的Y坐标偏移量与手势的位置的Y轴对齐。这样处理之后,cell 就像从 table view 中跳出,然后浮在上面,并捕捉到用户的手指。

static UIView       *snapshot = nil;        ///< A snapshot of the row user is moving.
static NSIndexPath  *sourceIndexPath = nil; ///< Initial index path, where gesture begins.
 
switch (state) {
  case UIGestureRecognizerStateBegan: {
    if (indexPath) {
      sourceIndexPath = indexPath;
 
      UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
 
      // Take a snapshot of the selected row using helper method.
      snapshot = [self customSnapshotFromView:cell];
 
      // Add the snapshot as subview, centered at cell's center...
      __block CGPoint center = cell.center;
      snapshot.center = center;
      snapshot.alpha = 0.0;
      [self.tableView addSubview:snapshot];
      [UIView animateWithDuration:0.25 animations:^{
 
        // Offset for gesture location.
        center.y = location.y;
        snapshot.center = center;
        snapshot.transform = CGAffineTransformMakeScale(1.05, 1.05);
        snapshot.alpha = 0.98;
 
        // Black out.
        cell.backgroundColor = [UIColor blackColor];
      } completion:nil];
    }
    break;
  }
  // More coming soon...
}

将下面的方法添加到 .m 文件的尾部。该方法会根据传入的 view,返回一个对应的 snapshot view。

- (UIView *)customSnapshotFromView:(UIView *)inputView {
 
  UIView *snapshot = [inputView snapshotViewAfterScreenUpdates:YES];
  snapshot.layer.masksToBounds = NO;
  snapshot.layer.cornerRadius = 0.0;
  snapshot.layer.shadowOffset = CGSizeMake(-5.0, 0.0);
  snapshot.layer.shadowRadius = 5.0;
  snapshot.layer.shadowOpacity = 0.4;
 
  return snapshot;
}

当手势移动的时候,也就是 UIGestureRecognizerStateChanged 分支,此时需要移动 snapshot view(只需要设置它的 Y 轴偏移量即可)。如果手势移动的距离对应到另外一个 index path,就需要告诉 table view,让其移动 rows。同时,你需要对 data source 进行更新:

case UIGestureRecognizerStateChanged: {
  CGPoint center = snapshot.center;
  center.y = location.y;
  snapshot.center = center;
 
  // Is destination valid and is it different from source?
  if (indexPath && ![indexPath isEqual:sourceIndexPath]) {
 
    // ... update data source.
    [self.objects exchangeObjectAtIndex:indexPath.row withObjectAtIndex:sourceIndexPath.row];
 
    // ... move the rows.
    [self.tableView moveRowAtIndexPath:sourceIndexPath toIndexPath:indexPath];
 
    // ... and update source so it is in sync with UI changes.
    sourceIndexPath = indexPath;
  }
  break;
}
// More coming soon...

最后,当手势结束或者取消时,table view 和 data source 都是最新的。你所需要做的事情就是将 snapshot view 从 table view 中移除,并把 cell 的背景色还原为白色。

为了提升用户体验,我们将 snapshot view 淡出,并让其尺寸变小至与 cell 一样。这样看起来就像把 cell 放回原处一样。

default: {
  // Clean up.
  UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:sourceIndexPath];
  [UIView animateWithDuration:0.25 animations:^{
 
    snapshot.center = cell.center;
    snapshot.transform = CGAffineTransformIdentity;
    snapshot.alpha = 0.0;
 
    // Undo the black-out effect we did.
    cell.backgroundColor = [UIColor whiteColor];
 
  } completion:^(BOOL finished) {
 
    [snapshot removeFromSuperview];
    snapshot = nil;
 
  }];
  sourceIndexPath = nil;
  break;
}

就这样,搞定了!编译并运行程序,现在可以通过长按手势对 tableview cells重新排序!


如何将其利用至UICollectionView上?

假设你已经有一个示例工程使用了 UICollectionView,那么你可以很简单的就使用上本文之前介绍的代码。所需要做的事情就是用self.collectionView替换掉 self.tableView,并更新一下获取和移动 UICollectionViewCell 的调用方法。


转自:破船的博客

原文地址:http://ios.9tech.cn/news/2014/0328/40129.html




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值