iOS开发UICollectionView拖拽移动单元格
一.介绍
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拖拽移动单元格相关推荐
- iOS开发storyboard拖拽tableView: Static cells的使用
从 object library 中,拖拽一个 UITableView 到 main.storyboard的 UIViewController 中: 设置 table view 的类型为: Sta ...
- 快速开发平台网格部件合并单元格。
度量快速开发平台中网格部件中的单元格,在合并的时候触发,根据实现代码的内容来判断哪些单元格可以合并,哪些单元格不能合并.注意:要启用单元格合并事件,需要先设置网格部件的属性"允许单元格合并& ...
- iOS基础-高级视图-UITableView--静态单元格
静态单元格 适用场合:分为好几组且图标和内容不规则.并且百年不变动. 1.新建一个MJViewController,继承自TableViewController 2.将storyboard的控制器Vi ...
- java excel单元格数据格式_POI实战-java开发excel详解之单元格各类型数据读取
2.复杂读取 2.1 单元格各类型数据读取 2.1.1 基本类型 在实际工作中,我们处理的Excel数据都不止限于字符型数据,更多的是数字.日期.甚至公式等. 下面是单元格类型说明: 类型 CELL_ ...
- iOS复习记录日记07-静态单元格和qq好友分组功能[2020]
前文 这是第7篇 主要记录下静态单元格,顾名思义,一旦设置好后,内容是不可被改变的 一般用于 不可改变的固定单元格列表展示,必须使用uiviewController才可用静态单元格 在uiviewCo ...
- iOS开发- UICollectionView详解+实例
本章通过先总体介绍UICollectionView及其常用方法,再结合一个实例,了解如何使用UICollectionView. UICollectionView 和 UICollectionViewC ...
- GeneXus开发平台 拖拽低代码 JNPF源码,java开源快速开发平台
GeneXus开发平台 GeneXus是一个敏捷的开发平台,使您的公司轻松应对技术的发展.GeneXus极大的简化了软件程序的开发过程,能自动生成从数据库到代码.前端到后端.服务器端到客户端服务的所有 ...
- 吴裕雄 Bootstrap 前端框架开发——Bootstrap 辅助类:表格单元格使用了 bg-primary 类...
<!DOCTYPE html> <html><head><meta charset="utf-8"> <title>菜鸟 ...
- 利用HTML5新特性实现拖拽交换表格单元格元素
利用HTML5新特性实现拖拽交换表格单元格元素 HTML5新特性:拖放 拖放 拖放(Drag 和 Drop)是很常见的特性.它指的是您抓取某物并拖入不同的位置. 拖放是 HTML5 标准的组成部分:任 ...
最新文章
- 一个IO的传奇一生(8) -- elevator子系统
- POSIX规范-unbuffered I/O (文件I/O)
- 【转】HTML中的map标签
- 爆料图显示iPhone 14 Pro及Max机身更厚 摄像头凸起也更多
- 字节流相关操作,基本字节流的Copy文件
- Flutter进阶—实现动画效果(七)
- acm java题_【转】ACM中java的使用
- Java解析函数_Java Predicate及Consumer接口函数代码实现解析
- spring实战笔记6---springMVC的请求过程
- Linux下编写udp群聊室
- ARDUINO LCD显示简单的汉字、符号(保姆级教程!)
- java输出精度到0.1_【java】浮点数精度问题,为什么0.1===0.1 5+0.1 = 5.1?
- 《打造Facebook》书摘(1):CEO小扎
- 我在哪?(寒假每日一题 35)
- 详细阅读Spark论文
- python解决字符串倒序输出
- SpringBoot 提示转换异常:java.lang.ClassCastException: com.*** cannot be cast to java.lang.String
- manjaro 安装搜狗输入法不显示候选词
- *SAS语言结构**
- 关于搞国外网赚的一些思路