一.介绍
ios9提供api实现单元格排序功能,使用uicollectionview及其代理方法。ios9之后有自带方法可以实现该效果,只需添加长按手势,实现手势方法和调用ios9的api交换数据,ios9之前需要自己写方法实现这效果,除了要添加长按手势,这里还需要利用截图替换原理,手动计算移动位置来处理视图交换和数据交换。
二.方法和步骤
1.创建工程项目和视图控制器,如下图
2.声明对象和设置代理和数据源代理
1
2
3
4
5
6
7
8
9
10
11
12
|
@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中初始化
1
2
3
4
5
6
7
8
9
10
11
12
13
|
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中初始化
1
2
3
4
5
6
7
8
|
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的两个必须实现的方法
1
2
3
4
5
6
7
8
9
10
11
12
|
#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.重点来了,实现长按手势方法
1
2
3
4
5
6
7
8
9
|
#pragma mark - 长按手势
- ( void )handlelonggesture:(uilongpressgesturerecognizer *)longpress
{
if ([[[uidevice currentdevice] systemversion] floatvalue] < 9.0) {
[self action:longpress];
} else {
[self ios9_action:longpress];
}
}
|
7.ios9之后的实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
|
#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之前的实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
|
#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如下
1
2
3
4
5
|
// 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);
|
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。
原文链接:https://blog.csdn.net/wgl_happy/article/details/52179608