在开发中大家可能遇到这么一种需求:有一个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;
}