长按移动cell

本文介绍了一种通过手势拖动来改变TableView中Cell位置的方法。实现方式包括添加长按手势、截图替换Cell、移动截图及数据源更新等步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言: 之前见过瀑布流中的cell,由手势拖动变换位置的效果,一直觉得很炫很神奇。今天无意在破船之家看到了这种效果的实现方法。最核心的位置变换只需掉俩个方法,然后由系统完成。所以很简单,没有想象中的那么复杂。

我们先从简单的Tableview开始。
效果如下
效果图

实现过程

  • 给tableview添加长按手势。
  • 在手势开始时,获取选中的cell,对cell截图。cell隐藏,截图的frame和cell的frame相同,也就是用截图替换掉cell。
  • 为了良好的用户体验,将截图放大一点,并设置上阴影效果,让截图跃然于纸上。
  • 手势移动时,移动截图。
  • 移动数据源中数据位置,
  • 移动cell的位置。调用这个方法。- (void)moveRowAtIndexPath:(NSIndexPath *)indexPath toIndexPath:(NSIndexPath *)newIndexPath
  • 手势结束时,移除截图,让cell重新显示出来。当然在这个过程中可以来点动画,让效果更炫点。

代码
添加长按手势的代码就不列出来了,这里是处理手势事件的方法。

- (void)handleLongPress:(UILongPressGestureRecognizer *)longPress
{
    CGPoint pressLocation = [longPress locationInView:self.tableView];

    NSIndexPath *currentIndexPath = [self.tableView indexPathForRowAtPoint:pressLocation];

    static NSIndexPath *sourceIndexPath = nil;
    static UIView *snapShot = nil;

    if (!currentIndexPath) return;

    if (longPress.state == UIGestureRecognizerStateBegan)
    {
        if (currentIndexPath) {
            // 0. 记录选中的indexPath
            sourceIndexPath = currentIndexPath;

            // 1. 截取cell上的图片
            UITableViewCell *sourceCell = [self.tableView cellForRowAtIndexPath:sourceIndexPath];
            snapShot = [self snapShotInView:sourceCell];
            snapShot.frame = sourceCell.frame;
            snapShot.alpha = 0;
            [self.tableView addSubview:snapShot];

            // 2. 对截图做动画,并隐藏cell
            [UIView animateWithDuration:0.5 animations:^{
                snapShot.transform = CGAffineTransformMakeScale(1.05, 1.05);
                snapShot.alpha = 0.9;
                sourceCell.alpha = 0.0f;

                CGPoint o = snapShot.center;
                o.y = pressLocation.y;
                snapShot.center = o;
            } completion:^(BOOL finished) {
                sourceCell.hidden = YES;
            }];
        }
    }
    else if (longPress.state == UIGestureRecognizerStateChanged)
    {
        // 移动截图
        CGPoint o = snapShot.center;
        o.y = pressLocation.y;
        snapShot.center = o;

        if (![currentIndexPath isEqual:sourceIndexPath]) {
            // 数据交换
            [self.datas exchangeObjectAtIndex:currentIndexPath.row withObjectAtIndex:sourceIndexPath.row];

            // cell移动
            [self.tableView moveRowAtIndexPath:sourceIndexPath toIndexPath:currentIndexPath];

            // 更新indexPath
            sourceIndexPath = currentIndexPath;
        }
    }
    else if (longPress.state == UIGestureRecognizerStateEnded)
    {
        // 截图动画消失,并且显示cell
        UITableViewCell *sourceCell = [self.tableView cellForRowAtIndexPath:sourceIndexPath];
        sourceCell.hidden = NO;
        sourceCell.alpha = 0.0f;

        [UIView animateWithDuration:0.25 animations:^{
            snapShot.center = sourceCell.center;
            snapShot.transform = CGAffineTransformIdentity;
            sourceCell.alpha = 1.0f;
        } completion:^(BOOL finished) {
            [snapShot removeFromSuperview];
        }];
    }
}
- (UIView *)snapShotInView:(UIView *)inputView
{
    UIView *snapShot = [inputView snapshotViewAfterScreenUpdates:NO];
    snapShot.bounds = inputView.bounds;
    snapShot.layer.shadowOffset = CGSizeMake(-5, 0);
    snapShot.layer.shadowOpacity = 1;
    snapShot.layer.shadowRadius = 5.0;
    return snapShot;
}
  1. if (!currentIndexPath) return; 因为如果选到了section的段头上,currentIndexPath是空值。所以要判断。
  2. sourceIndexPath 表示的是交换后源cell的索引。也就是cell移动到了哪个位置上。
  3. 移动的核心代码就这俩句,[self.datas exchangeObjectAtIndex:currentIndexPath.row withObjectAtIndex:sourceIndexPath.row];和[self.tableView moveRowAtIndexPath:sourceIndexPath toIndexPath:currentIndexPath];先更新数据源,然后更新UI,这个没什么好讲的了。最后别忘记sourceIndexPath = currentIndexPath;移动后源cell的位置也发生变化,所以要更新哦。

CollectionView和上面的过程几乎一模一样。
附上效果图
这里写图片描述

TableView的Demo

CollectionView的Demo

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值