iOS开发UICollectionView实现拖拽效果
程序员文章站
2023-11-22 11:10:04
一.介绍
ios9提供api实现单元格排序功能,使用uicollectionview及其代理方法。ios9之后有自带方法可以实现该效果,只需添加长按手势,实现手势方法和调...
一.介绍
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.0 cgfloat saturation = (arc4random()%128/256.0)+0.5; //0.5 到 1.0 cgfloat brightness = (arc4random()%128/256.0)+0.5; //0.5 到 1.0 uicolor *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]; // 截图后隐藏当前cell cell.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就不需要交换了,直接continue if ([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]; //设置移动后的起始indexpath self.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);
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
上一篇: C# 编码好习惯,献给所有热爱c#的同志