一.介绍

iOS9提供API实现单元格排序呢功能,使用UICollectionView及其代理方法.iOS9之后有自带方法可以实现该效果,只需添加长按手势,实现手势方法和调用iOS9的API交换数据,iOS9之前需要自己写方法实现这效果,除了要添加长按手势,这里还需要利用截图替换原理,手动计算移动位置来处理视图交换和数据交换.

二.方法和步骤

1.创建工程项目和视图控制器,如下图

2.声明对象和设置代理和数据源代理

@interface ViewController ()<UICollectionViewDelegate,UICollectionViewDataSource,UICollectionViewDelegateFlowLayout>@property (nonatomic, strong) NSMutableArray *dataArr;
@property (nonatomic, strong) UICollectionView *collectionView;
/**之前选中cell的NSIndexPath*/
@property (nonatomic, strong) NSIndexPath *oldIndexPath;
/**单元格的截图*/
@property (nonatomic, strong) UIView *snapshotView;
/**之前选中cell的NSIndexPath*/
@property (nonatomic, strong) NSIndexPath *moveIndexPath;@end

3.初始化UICollectionView,并添加长按手势,在viewDidLoad中初始化

CGFloat SCREEN_WIDTH = self.view.frame.size.width;UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];flowLayout.itemSize = CGSizeMake((SCREEN_WIDTH-40.0)/3, (SCREEN_WIDTH-40.0)/3);UICollectionView *collectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(0, 50.0, SCREEN_WIDTH, (SCREEN_WIDTH-40.0)/3+20.0) collectionViewLayout:flowLayout];collectionView.dataSource = self;collectionView.delegate = self;collectionView.backgroundColor = [UIColor whiteColor];[collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:@"uicollectionviewcell"];[self.view addSubview:self.collectionView = collectionView];// 添加长按手势UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handlelongGesture:)];[collectionView addGestureRecognizer:longPress];

4.实例化数据源,(50个随机颜色,透明度0.8),在viewDidLoad中初始化

self.dataArr = [[NSMutableArray alloc] init];
for (NSInteger index = 0; index < 50; index ++) {CGFloat hue = (arc4random()%256/256.0); //0.0 到 1.0CGFloat saturation = (arc4random()%128/256.0)+0.5; //0.5 到 1.0CGFloat brightness = (arc4random()%128/256.0)+0.5; //0.5 到 1.0UIColor *color = [UIColor colorWithHue:hue saturation:saturation brightness:brightness alpha:0.5];[self.dataArr addObject:color];}

5.实现UICollectionView的UICollectionViewDataSource的两个必须实现的方法

#pragma mark - UICollectionViewDataSource
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{return self.dataArr.count;
}- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"uicollectionviewcell" forIndexPath:indexPath];cell.backgroundColor = self.dataArr[indexPath.row];return cell;
}

6.重点来了,实现长按手势方法

#pragma mark - 长按手势
- (void)handlelongGesture:(UILongPressGestureRecognizer *)longPress
{if ([[[UIDevice currentDevice] systemVersion] floatValue] < 9.0) {[self action:longPress];} else {[self iOS9_Action:longPress];}
}

7.iOS9之后的实现

#pragma mark - iOS9 之后的方法
- (BOOL)collectionView:(UICollectionView *)collectionView canMoveItemAtIndexPath:(NSIndexPath *)indexPath
{// 返回YES允许row移动return YES;
}- (void)collectionView:(UICollectionView *)collectionView moveItemAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath
{//取出移动row数据id color = self.dataArr[sourceIndexPath.row];//从数据源中移除该数据[self.dataArr removeObject:color];//将数据插入到数据源中的目标位置[self.dataArr insertObject:color atIndex:destinationIndexPath.row];
}- (void)iOS9_Action:(UILongPressGestureRecognizer *)longPress
{switch (longPress.state) {case UIGestureRecognizerStateBegan:{ //手势开始//判断手势落点位置是否在row上NSIndexPath *indexPath = [self.collectionView indexPathForItemAtPoint:[longPress locationInView:self.collectionView]];if (indexPath == nil) {break;}UICollectionViewCell *cell = [self.collectionView cellForItemAtIndexPath:indexPath];[self.view bringSubviewToFront:cell];//iOS9方法 移动cell[self.collectionView beginInteractiveMovementForItemAtIndexPath:indexPath];}break;case UIGestureRecognizerStateChanged:{ // 手势改变// iOS9方法 移动过程中随时更新cell位置[self.collectionView updateInteractiveMovementTargetPosition:[longPress locationInView:self.collectionView]];}break;case UIGestureRecognizerStateEnded:{ // 手势结束// iOS9方法 移动结束后关闭cell移动[self.collectionView endInteractiveMovement];}break;default: //手势其他状态[self.collectionView cancelInteractiveMovement];break;}
}

8.iOS9之前的实现

#pragma mark - iOS9 之前的方法
- (void)action:(UILongPressGestureRecognizer *)longPress
{switch (longPress.state) {case UIGestureRecognizerStateBegan:{ // 手势开始//判断手势落点位置是否在row上NSIndexPath *indexPath = [self.collectionView indexPathForItemAtPoint:[longPress locationInView:self.collectionView]];self.oldIndexPath = indexPath;if (indexPath == nil) {break;}UICollectionViewCell *cell = [self.collectionView cellForItemAtIndexPath:indexPath];// 使用系统的截图功能,得到cell的截图视图UIView *snapshotView = [cell snapshotViewAfterScreenUpdates:NO];snapshotView.frame = cell.frame;[self.view addSubview:self.snapshotView = snapshotView];// 截图后隐藏当前cellcell.hidden = YES;CGPoint currentPoint = [longPress locationInView:self.collectionView];[UIView animateWithDuration:0.25 animations:^{snapshotView.transform = CGAffineTransformMakeScale(1.05, 1.05);snapshotView.center = currentPoint;}];}break;case UIGestureRecognizerStateChanged:{ // 手势改变//当前手指位置 截图视图位置随着手指移动而移动CGPoint currentPoint = [longPress locationInView:self.collectionView];self.snapshotView.center = currentPoint;// 计算截图视图和哪个可见cell相交for (UICollectionViewCell *cell in self.collectionView.visibleCells) {// 当前隐藏的cell就不需要交换了,直接continueif ([self.collectionView indexPathForCell:cell] == self.oldIndexPath) {continue;}// 计算中心距CGFloat space = sqrtf(pow(self.snapshotView.center.x - cell.center.x, 2) + powf(self.snapshotView.center.y - cell.center.y, 2));// 如果相交一半就移动if (space <= self.snapshotView.bounds.size.width / 2) {self.moveIndexPath = [self.collectionView indexPathForCell:cell];//移动 会调用willMoveToIndexPath方法更新数据源[self.collectionView moveItemAtIndexPath:self.oldIndexPath toIndexPath:self.moveIndexPath];//设置移动后的起始indexPathself.oldIndexPath = self.moveIndexPath;break;}}}break;default:{ // 手势结束和其他状态UICollectionViewCell *cell = [self.collectionView cellForItemAtIndexPath:self.oldIndexPath];// 结束动画过程中停止交互,防止出问题self.collectionView.userInteractionEnabled = NO;// 给截图视图一个动画移动到隐藏cell的新位置[UIView animateWithDuration:0.25 animations:^{self.snapshotView.center = cell.center;self.snapshotView.transform = CGAffineTransformMakeScale(1.0, 1.0);} completion:^(BOOL finished) {// 移除截图视图,显示隐藏的cell并开始交互[self.snapshotView removeFromSuperview];cell.hidden = NO;self.collectionView.userInteractionEnabled = YES;}];}break;}
}

三.iOS9之后添加的API如下

// Support for reordering
- (BOOL)beginInteractiveMovementForItemAtIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(9_0); // returns NO if reordering was prevented from beginning - otherwise YES
- (void)updateInteractiveMovementTargetPosition:(CGPoint)targetPosition NS_AVAILABLE_IOS(9_0);
- (void)endInteractiveMovement NS_AVAILABLE_IOS(9_0);
- (void)cancelInteractiveMovement NS_AVAILABLE_IOS(9_0);

iOS开发UICollectionView拖拽移动单元格相关推荐

  1. iOS开发storyboard拖拽tableView: Static cells的使用

    从 object library 中,拖拽一个 UITableView 到 main.storyboard的 UIViewController 中: 设置  table view 的类型为:  Sta ...

  2. 快速开发平台网格部件合并单元格。

    度量快速开发平台中网格部件中的单元格,在合并的时候触发,根据实现代码的内容来判断哪些单元格可以合并,哪些单元格不能合并.注意:要启用单元格合并事件,需要先设置网格部件的属性"允许单元格合并& ...

  3. iOS基础-高级视图-UITableView--静态单元格

    静态单元格 适用场合:分为好几组且图标和内容不规则.并且百年不变动. 1.新建一个MJViewController,继承自TableViewController 2.将storyboard的控制器Vi ...

  4. java excel单元格数据格式_POI实战-java开发excel详解之单元格各类型数据读取

    2.复杂读取 2.1 单元格各类型数据读取 2.1.1 基本类型 在实际工作中,我们处理的Excel数据都不止限于字符型数据,更多的是数字.日期.甚至公式等. 下面是单元格类型说明: 类型 CELL_ ...

  5. iOS复习记录日记07-静态单元格和qq好友分组功能[2020]

    前文 这是第7篇 主要记录下静态单元格,顾名思义,一旦设置好后,内容是不可被改变的 一般用于 不可改变的固定单元格列表展示,必须使用uiviewController才可用静态单元格 在uiviewCo ...

  6. iOS开发- UICollectionView详解+实例

    本章通过先总体介绍UICollectionView及其常用方法,再结合一个实例,了解如何使用UICollectionView. UICollectionView 和 UICollectionViewC ...

  7. GeneXus开发平台 拖拽低代码 JNPF源码,java开源快速开发平台

    GeneXus开发平台 GeneXus是一个敏捷的开发平台,使您的公司轻松应对技术的发展.GeneXus极大的简化了软件程序的开发过程,能自动生成从数据库到代码.前端到后端.服务器端到客户端服务的所有 ...

  8. 吴裕雄 Bootstrap 前端框架开发——Bootstrap 辅助类:表格单元格使用了 bg-primary 类...

    <!DOCTYPE html> <html><head><meta charset="utf-8"> <title>菜鸟 ...

  9. 利用HTML5新特性实现拖拽交换表格单元格元素

    利用HTML5新特性实现拖拽交换表格单元格元素 HTML5新特性:拖放 拖放 拖放(Drag 和 Drop)是很常见的特性.它指的是您抓取某物并拖入不同的位置. 拖放是 HTML5 标准的组成部分:任 ...

最新文章

  1. 一个IO的传奇一生(8) -- elevator子系统
  2. POSIX规范-unbuffered I/O (文件I/O)
  3. 【转】HTML中的map标签
  4. 爆料图显示iPhone 14 Pro及Max机身更厚 摄像头凸起也更多
  5. 字节流相关操作,基本字节流的Copy文件
  6. Flutter进阶—实现动画效果(七)
  7. acm java题_【转】ACM中java的使用
  8. Java解析函数_Java Predicate及Consumer接口函数代码实现解析
  9. spring实战笔记6---springMVC的请求过程
  10. Linux下编写udp群聊室
  11. ARDUINO LCD显示简单的汉字、符号(保姆级教程!)
  12. java输出精度到0.1_【java】浮点数精度问题,为什么0.1===0.1 5+0.1 = 5.1?
  13. 《打造Facebook》书摘(1):CEO小扎
  14. 我在哪?(寒假每日一题 35)
  15. 详细阅读Spark论文
  16. python解决字符串倒序输出
  17. SpringBoot 提示转换异常:java.lang.ClassCastException: com.*** cannot be cast to java.lang.String
  18. manjaro 安装搜狗输入法不显示候选词
  19. *SAS语言结构**
  20. 关于搞国外网赚的一些思路

热门文章

  1. python直方图分箱_5种方法教你用Python玩转histogram直方图
  2. 在普林斯顿大学做助理教授的日子--施一公教授
  3. 29岁vivo员工吐槽:mysqlexists和in的区别
  4. 数据库2——简单 单表查询(50)
  5. 【学习笔记62】判断数据类型的方法
  6. 阿里云域名购买流程以及免费证书的申请(八)
  7. 为什么别家宝宝一觉到天亮,同是母乳喂养,你家宝宝却频繁夜醒?
  8. bat快速创建大量文件
  9. httpbin的使用
  10. 用python画花瓣 随机花瓣数_纯干货分享!几种常用的没骨花瓣的画法