IOS UITableViewCell跟随手指移动功能

 在开发中大家可能遇到这么一种需求:有一个UITableView,长按cell过后cell跟随着用户的手指移动,手指松开cell停留在当前的位置,并且UITableView的布局也会重排。值得一提的是UICollectionView如果需要实现这个功能好办的多,因为UICollectionView本来就有UI重排的方法提供给我们,但是UITableView得我们自己来实现。UITableView实现的思路是:
 1.为整个UITableView添加长按手势
 2.封装一个方法,参数为UITableViewCell,这个方法的功能是将我们手指长按触摸的cell传入,并将传入的这个UITableViewCell截图,返回一个UIImage对象。
 3.定义一个UIImageView的属性或者全局变量,将步骤2生成的UIImage赋值给这个UIImageView,在长按手势移动的时候,我们移动的就是这个UIImageView。
 4.移动数据源
 上面是关键点:思路是:UITableView添加长按手势过后,触摸cell,我们获取到手指触摸的这个cell对象,并且将这个cell对象截图赋值给全局变量UIImageView,然后将获取到的这个cell.hidden = YES隐藏掉。当我们手指松开的时候,使用关键代码:[self.myTableview moveRowAtIndexPath:_currentPath toIndexPath:newIndexPath]移动cell,然后将这个UIImageView移除掉并且将我们开始隐藏的cell重新显示出来cell.hidden = NO;
 好了代码才解释的清楚,但是解释一下,我的代码中没有移动数据源这一步骤,请大家根据自己实际情况编写。注意点我都有注释!
 #import "ViewController.h"

define WIDTH [UIScreen mainScreen].bounds.size.width

define COUNT 10

@interface ViewController ()<
UITableViewDataSource,
UITableViewDelegate
>

@property(strong,nonatomic)UITableView*myTableview;
@property(strong,nonatomic)UIImageView *cellImage;
@property(strong,nonatomic)NSIndexPath *currentPath;
@property(strong,nonatomic)UITableViewCell *currentCell;
@property(assign,nonatomic)CGFloat orignY;

@end

@implementation ViewController

  • (void)viewDidLoad {

    [super viewDidLoad];

    [self.view addSubview:self.myTableview];

    UILongPressGestureRecognizer *pan=[[UILongPressGestureRecognizer alloc]initWithTarget:self action:@selector(panReg:)];

    [self.myTableview addGestureRecognizer:pan];

}

  • (void)viewDidAppear:(BOOL)animated{

    [super viewDidAppear:animated];

}

-(UITableViewCell*)tableView:(UITableView )tableView cellForRowAtIndexPath:(NSIndexPath )indexPath
{

static NSString *identify=@"testIdentify";

UITableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:identify];

if (!cell) {

    cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identify];

    cell.selectionStyle=UITableViewCellSelectionStyleNone;

}

//资源图片,大家可以添加自己的资源图片
cell.imageView.image=[UIImage imageNamed:[NSString stringWithFormat:@"taskicon0%lu",indexPath.row]];

cell.textLabel.text=[NSString stringWithFormat:@"taskIcon%lu",indexPath.row];

return cell;

}

-(CGFloat)tableView:(UITableView )tableView heightForRowAtIndexPath:(NSIndexPath )indexPath
{

return 60;

}

-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{

return COUNT;

}

-(void)tableView:(UITableView )tableView didSelectRowAtIndexPath:(NSIndexPath )indexPath
{

}

/*
- (CGPoint)translationInView:(nullable UIView *)view; // translation in the coordinate system of the specified view
- (void)setTranslation:(CGPoint)translation inView:(nullable UIView *)view;

  • (CGPoint)velocityInView:(nullable UIView *)view;
    */

//MARK:-PAN GESTURE
- (void)panReg:(UILongPressGestureRecognizer*)recognise{

CGPoint currentPoint = [recognise locationInView:self.myTableview];

if (recognise.state==UIGestureRecognizerStateBegan) {

    _orignY=currentPoint.y;
    _currentPath = [_myTableview indexPathForRowAtPoint:currentPoint];
    _currentCell=[_myTableview cellForRowAtIndexPath:_currentPath];
    _currentCell.hidden=YES;//隐藏长按的那个cell
    _cellImage =[UIImageView new];
    _cellImage.image=[self getImageWithCell:_currentCell];//将这个cell的样子截屏,成为一个image,放在UIImageView上。

// _cellImage.frame=CGRectMake(0,currentPoint.y, WIDTH, 60);
_cellImage.backgroundColor =[UIColor clearColor];

    [self.view addSubview:_cellImage];

}else if(recognise.state==UIGestureRecognizerStateChanged){

    _cellImage.frame=CGRectMake(0, currentPoint.y+30, WIDTH, 60);

    //判断方向
    if (currentPoint.y>_orignY) {

        if (currentPoint.y-_orignY>30) {

            NSIndexPath *newIndexPath=[NSIndexPath indexPathForRow:_currentPath.row+1 inSection:0];

            if(newIndexPath.row<COUNT){

                //移动
                [self.myTableview moveRowAtIndexPath:_currentPath toIndexPath:newIndexPath];

                //赋值给当前的路径,用来记录。
                _currentPath=newIndexPath;
                _orignY+=60;

            }

        }

    }else{

        if (_orignY-currentPoint.y>30) {//往上滑

            NSIndexPath *newIndexPath=[NSIndexPath indexPathForRow:_currentPath.row-1 inSection:0];

            [self.myTableview moveRowAtIndexPath:_currentPath toIndexPath:newIndexPath];

            _currentPath=newIndexPath;

            _orignY-=60;

        }

    }

}else if(recognise.state==UIGestureRecognizerStateEnded){

        //执行完毕,删除UIImageView和路径。
        [_cellImage removeFromSuperview];
        _cellImage=nil;
        _currentCell.hidden=NO;

}

}

//MARK:截图
- (UIImage )getImageWithCell:(UITableViewCell)cell {

// UIGraphicsBeginImageContextWithOptions
// 函数原型为:
// void UIGraphicsBeginImageContextWithOptions(CGSize size, BOOL opaque, CGFloat scale);
// size——同UIGraphicsBeginImageContext
// opaque—透明开关,如果图形完全不用透明,设置为YES以优化位图的存储。
// scale—–缩放因子 iPhone 4是2.0,其他是1.0。虽然这里可以用[UIScreen mainScreen].scale来获取,但实际上设为0后,系统就会自动设置正确的比例了。

UIGraphicsBeginImageContextWithOptions(CGSizeMake(WIDTH, 60), NO, 1.0);
CGContextRef context=UIGraphicsGetCurrentContext();

CGContextDrawImage(context, CGRectMake(0, 3, WIDTH, 60), [UIImage imageNamed:@"shadow"].CGImage);

[cell.contentView.layer renderInContext:context];

UIImage *image = UIGraphicsGetImageFromCurrentImageContext();

UIGraphicsEndImageContext();

return image;

}

//MARK:-GETTER
- (UITableView *)myTableview
{
if (!_myTableview) {

    _myTableview = [[UITableView alloc]initWithFrame:CGRectMake(0, 64, [UIScreen mainScreen].bounds.size.width,[UIScreen mainScreen].bounds.size.height-64)];
    _myTableview.delegate = self;
    _myTableview.dataSource = self;
    _myTableview.scrollEnabled = YES;

}
return _myTableview;

}

  • (UITableViewCellAccessoryType)tableView:(UITableView )tableView accessoryTypeForRowWithIndexPath:(NSIndexPath )indexPath{

    return UITableViewCellAccessoryDisclosureIndicator;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值