服务器之家:专注于服务器技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - IOS - 使用iOS控件UICollectionView生成可拖动的桌面的实例

使用iOS控件UICollectionView生成可拖动的桌面的实例

2021-02-23 15:14HelloWord杰少 IOS

本篇文章主要介绍了使用iOS控件UICollectionView生成可拖动的桌面,具有一定的参考价值,有需要的可以了解一下。

一个app受欢迎的程度,一方面来源于它本身为用户提供便捷的功能,另一方面则来源于它的ui。ui是用户体验重要的组成部分,构成ui的的元素恰恰离不开那些看似独立的控件。在开发的过程中,大家对uitableview应该很熟悉吧!确实uitableview在处理数据显示方面有着很强大的功能,例如网红们使用的微博,微信社交软件的聊天界面等等,这种流式布局使用uitableview简直最合适不过了;但毕竟uitableview不是万能的,当需要显示横纵向的数据时它就显得捉襟见肘了,虽然这也难不倒我们程序猿但是何必要大费周章的去定义复杂的cell呢!uicollectionview就是专门用来应付这种布局的,使用uicollectionview可以给我们带来以下几点优势:1.可以高度的定制内容展示的样式 2.高效的管理大量的数据。

首先给大家看一下这个demo的效果图:

使用iOS控件UICollectionView生成可拖动的桌面的实例

ios设备不知道现在有没有可以屏幕录制的app,这样我就可以把操作的动作用gif图片po上来了,大家如果有推荐可以告诉我哈!关于拖动,长按图片后就可以将图片拖到你想要的位置上,另外的图片则会依次排序,很顺畅的体验。

在使用uicollectionview的时后,我们的类需要实现这些协议:uicollectionviewdatasource,uicollectionviewdelegateflowlayout,

uicollectionviewdelegate,uigesturerecognizerdelegate。

uicollectionviewdatasource:和我们在uitableview中所需要实现的uitableviewdatasource是一个道理,它里面包括以下这些api:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@protocol uicollectionviewdatasource <nsobject>
@required
 
- (nsinteger)collectionview:(uicollectionview *)collectionview numberofitemsinsection:(nsinteger)section;
 
// the cell that is returned must be retrieved from a call to -dequeuereusablecellwithreuseidentifier:forindexpath:
- (uicollectionviewcell *)collectionview:(uicollectionview *)collectionview cellforitematindexpath:(nsindexpath *)indexpath;
 
@optional
 
- (nsinteger)numberofsectionsincollectionview:(uicollectionview *)collectionview;
 
// the view that is returned must be retrieved from a call to -dequeuereusablesupplementaryviewofkind:withreuseidentifier:forindexpath:
- (uicollectionreusableview *)collectionview:(uicollectionview *)collectionview viewforsupplementaryelementofkind:(nsstring *)kind atindexpath:(nsindexpath *)indexpath;
 
- (bool)collectionview:(uicollectionview *)collectionview canmoveitematindexpath:(nsindexpath *)indexpath ns_available_ios(9_0);
- (void)collectionview:(uicollectionview *)collectionview moveitematindexpath:(nsindexpath *)sourceindexpath toindexpath:(nsindexpath*)destinationindexpath ns_available_ios(9_0);
 
@end

uicollectionviewdelegateflowlayout:uicollectionviewflowlayout是一个专门用来管理collectionview布局的类,可以通过实现以下函数来调整我们界面的样式:

?
1
2
3
4
5
6
7
8
9
10
11
@protocol uicollectionviewdelegateflowlayout <uicollectionviewdelegate>
@optional
 
- (cgsize)collectionview:(uicollectionview *)collectionview layout:(uicollectionviewlayout*)collectionviewlayout sizeforitematindexpath:(nsindexpath *)indexpath;
- (uiedgeinsets)collectionview:(uicollectionview *)collectionview layout:(uicollectionviewlayout*)collectionviewlayout insetforsectionatindex:(nsinteger)section;
- (cgfloat)collectionview:(uicollectionview *)collectionview layout:(uicollectionviewlayout*)collectionviewlayout minimumlinespacingforsectionatindex:(nsinteger)section;
- (cgfloat)collectionview:(uicollectionview *)collectionview layout:(uicollectionviewlayout*)collectionviewlayout minimuminteritemspacingforsectionatindex:(nsinteger)section;
- (cgsize)collectionview:(uicollectionview *)collectionview layout:(uicollectionviewlayout*)collectionviewlayout referencesizeforheaderinsection:(nsinteger)section;
- (cgsize)collectionview:(uicollectionview *)collectionview layout:(uicollectionviewlayout*)collectionviewlayout referencesizeforfooterinsection:(nsinteger)section;
 
@end

uicollectionviewdelegate:和uitableviewdelegate一样,这里就把它协议里面的的函数po出来了,通过重写里面的函数,我们可以实现cell的点击与拖动。

uigesturerecognizerdelegate:由于我们还有一个拖动的功能,所以需要实现用户手势的协议。

好了,基础的概念讲了,现在我们就开始动手实现他吧!老样子直接看源码:

?
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
- (void)viewdidload {
  [super viewdidload];
  // do any additional setup after loading the view, typically from a nib.
   
  //设置背景色
  [self.view setbackgroundcolor:[uicolor colorwithpatternimage:[uiimage imagenamed:@"back.jpg"]]];
  //设置数据源
  self.datasource = [[nsmutablearray alloc] initwithobjects:
            @"1.png",@"2.png",@"3.png", @"4.png", @"5.png", @"6.png", @"7.png", @"8.png", @"9.png", @"10.png", @"11.jpg", @"12.jpg",
            @"13.jpg", @"14.jpg", @"15.jpg", @"16.png", @"17.png", @"18.png", @"19.png", @"20.png", nil nil];
  //初始化布局
  self.flow = [[uicollectionviewflowlayout alloc] init];
  self.collect = [[uicollectionview alloc] initwithframe:cgrectzero collectionviewlayout:self.flow];
  [self.collect setbackgroundcolor:[uicolor clearcolor]];
   
  //注册cell 这一步必须要实现
  [self.collect registerclass:[customcollectioncell class] forcellwithreuseidentifier:@"customcell"];
   
  self.collect.delegate = self;
  self.collect.datasource = self;
   
  [self.collect setframe:self.view.bounds];
   
  //添加长按手势
  self.longpressgesturerecognizer = [[uilongpressgesturerecognizer alloc] init];
  [self.longpressgesturerecognizer addtarget:self action:@selector(handlelongpressrecognizer:)];
  [self.collect addgesturerecognizer:self.longpressgesturerecognizer];
   
  [self.view addsubview:self.collect];
}

在viewdidload函数中,初始化了一个uicollectionviewflowlayout布局,并且需要配合uicollectionview来使用,两者加一起来使用才能“完美”,想比uitableview 中cell使用的不同,在uicollectionview中必须先对cell进行注册(registerclass),不然会在运行过程中报错。如何使排列的图片可以拖动呢,在这里我为uicollectionview添加了一个长按手势uilongpressgesturerecognizer。当我们长按时会触发handlelongpressrecognizer,代码如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
- (void)handlelongpressrecognizer:(uilongpressgesturerecognizer *)gesture{
  switch (gesture.state) {
    case uigesturerecognizerstatebegan:{
      nsindexpath *path = [self.collect indexpathforitematpoint:[gesture locationinview:gesture.view]];
      if(path == nil){
        break;
      }
       
      [self.collect begininteractivemovementforitematindexpath:path];
    }
      break;
    case uigesturerecognizerstatechanged:
      [self.collect updateinteractivemovementtargetposition:[gesture locationinview:gesture.view]];
      break;
    case uigesturerecognizerstateended:
      [self.collect endinteractivemovement];
      break;
    default:
      [self.collect cancelinteractivemovement];
      break;
  }
}

好看的界面才能抓住用户的心,这里我自定义了cell继承自uicollectionviewcell,cell中展示的图片会根据自身图片的大小进行按比例缩放,这样我们的桌面看上去就会有横版图片与竖版图片,如果不自定义的话就都是方方正正的九宫格,还是花点心思自定义一下显示效果吧!customcollectioncell的的代码如下:

?
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
#import "customcollectioncell.h"
 
@implementation customcollectioncell
@synthesize imagev = _imagev;
@synthesize labelv = _labelv;
@synthesize boundview = _boundview;
 
- (id)initwithframe:(cgrect) frame{
  self = [super initwithframe:frame];
  //init attributes
  if(self){
    [self setbackgroundcolor:[uicolor clearcolor]];
    self.imagev = [[uiimageview alloc] initwithframe:cgrectzero];
    self.labelv = [[uilabel alloc] initwithframe:cgrectzero];
    self.boundview = [[uiview alloc] initwithframe:cgrectzero];
    [self.boundview setbackgroundcolor:[uicolor whitecolor]];
    [self.boundview addsubview:self.imagev];
    [self addsubview:self.boundview];
    [self addsubview:self.labelv];
  }
   
  return self;
}
 
- (void)setimagewithtext:(uiimage *)image text:(nsstring *)text{
  if(!image){
    return;
  }
   
  cgfloat imgwidth = image.size.width;
  cgfloat imgheight = image.size.height;
  cgfloat iconwidth = 0.0;
  cgfloat iconheight = 0.0;
   
  if(imgwidth > imgheight){
    iconheight = roundf(((self.frame.size.width - 16)*imgheight)/imgwidth);
    iconwidth = self.frame.size.width - 16;
    [self.boundview setframe:cgrectmake(0, self.frame.size.height - iconheight - 16, iconwidth + 16, iconheight + 16)];
    [self.imagev setframe:cgrectmake(8, 8, iconwidth, iconheight)];
  }else{
    iconwidth = roundf(((self.frame.size.width - 16) *imgwidth)/imgheight);
    iconheight = self.frame.size.height - 16;
    [self.boundview setframe:cgrectmake(roundf((self.frame.size.width - iconwidth)/2), 0, iconwidth + 16, iconheight + 16)];
    [self.imagev setframe:cgrectmake(8, 8, iconwidth, iconheight)];
  }
   
  [self.imagev setimage:image];
}
 
@end

以上这些就是构成该demo的重要组成部分了,uicollectionview还有很多的要素在这里面没有讲到,往后我还会再研究这个控件更加高级的的使用,本篇就好比是餐前的开胃小菜吧,希望大家喜欢。附上这个例子的源码:

?
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
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
@implementation viewcontroller
@synthesize datasource = _datasource;
@synthesize longpressgesturerecognizer = _longpressgesturerecognizer;
@synthesize flow = _flow;
@synthesize collect = _collect;
 
- (void)viewdidload {
  [super viewdidload];
  // do any additional setup after loading the view, typically from a nib.
   
  //设置背景色
  [self.view setbackgroundcolor:[uicolor colorwithpatternimage:[uiimage imagenamed:@"back.jpg"]]];
  //设置数据源
  self.datasource = [[nsmutablearray alloc] initwithobjects:
            @"1.png",@"2.png",@"3.png", @"4.png", @"5.png", @"6.png", @"7.png", @"8.png", @"9.png", @"10.png", @"11.jpg", @"12.jpg",
            @"13.jpg", @"14.jpg", @"15.jpg", @"16.png", @"17.png", @"18.png", @"19.png", @"20.png", nil nil];
  //初始化布局
  self.flow = [[uicollectionviewflowlayout alloc] init];
  self.collect = [[uicollectionview alloc] initwithframe:cgrectzero collectionviewlayout:self.flow];
  [self.collect setbackgroundcolor:[uicolor clearcolor]];
   
  //注册cell 这一步必须要实现
  [self.collect registerclass:[customcollectioncell class] forcellwithreuseidentifier:@"customcell"];
   
  self.collect.delegate = self;
  self.collect.datasource = self;
   
  [self.collect setframe:self.view.bounds];
   
  //添加长按手势
  self.longpressgesturerecognizer = [[uilongpressgesturerecognizer alloc] init];
  [self.longpressgesturerecognizer addtarget:self action:@selector(handlelongpressrecognizer:)];
  [self.collect addgesturerecognizer:self.longpressgesturerecognizer];
   
  [self.view addsubview:self.collect];
}
 
- (void)didreceivememorywarning {
  [super didreceivememorywarning];
  // dispose of any resources that can be recreated.
}
 
- (void)handlelongpressrecognizer:(uilongpressgesturerecognizer *)gesture{
  switch (gesture.state) {
    case uigesturerecognizerstatebegan:{
      nsindexpath *path = [self.collect indexpathforitematpoint:[gesture locationinview:gesture.view]];
      if(path == nil){
        break;
      }
       
      [self.collect begininteractivemovementforitematindexpath:path];
    }
      break;
    case uigesturerecognizerstatechanged:
      [self.collect updateinteractivemovementtargetposition:[gesture locationinview:gesture.view]];
      break;
    case uigesturerecognizerstateended:
      [self.collect endinteractivemovement];
      break;
    default:
      [self.collect cancelinteractivemovement];
      break;
  }
}
 
#pragma mark uicollectionviewdatasource
- (nsinteger)collectionview:(uicollectionview *)collectionview numberofitemsinsection:(nsinteger)section{
  return self.datasource.count;
}
 
- (nsinteger)numberofsectionsincollectionview:(uicollectionview *)collectionview{
  return 1;
}
 
- (uicollectionviewcell *)collectionview:(uicollectionview *)collectionview cellforitematindexpath:(nsindexpath *)indexpath{
  customcollectioncell * cell = (customcollectioncell *)[collectionview dequeuereusablecellwithreuseidentifier:@"customcell" forindexpath:indexpath];
  uiimage *image = [uiimage imagenamed:[self.datasource objectatindex:indexpath.row]];
  [cell setimagewithtext:image text:@""];
   
  return cell;
}
 
- (bool)collectionview:(uicollectionview *)collectionview canmoveitematindexpath:(nsindexpath *)indexpath{
  return yes;
}
 
- (void)collectionview:(uicollectionview *)collectionview moveitematindexpath:(nsindexpath *)sourceindexpath toindexpath:(nsindexpath*)destinationindexpath{
   
  id item = [self.datasource objectatindex:sourceindexpath.item];
  [self.datasource removeobject:item];
   
  [self.datasource insertobject:item atindex:destinationindexpath.item];
}
 
#pragma mark uicollectionviewdelegate
- (void)collectionview:(uicollectionview *)collectionview didselectitematindexpath:(nsindexpath *)indexpath{
  testviewcontroller *test = [[testviewcontroller alloc] initwithnibname:@"testviewcontroller" bundle:nil];
  nsstring *imagename = [self.datasource objectatindex:indexpath.row];
  test.imagename = imagename;
   
  [self.navigationcontroller pushviewcontroller:test animated:yes];
}
 
- (bool)collectionview:(uicollectionview *)collectionview shouldhighlightitematindexpath:(nsindexpath *)indexpath{
  return yes;
}
 
//选中放大效果
- (void)collectionview:(uicollectionview *)collectionview didhighlightitematindexpath:(nsindexpath *)indexpath{
//  customcollectioncell * cell = (customcollectioncell *)[collectionview cellforitematindexpath:indexpath];
//  
//  [uiview animatewithduration:1 animations:^{
//    cell.transform = cgaffinetransformmakescale(2.0f, 2.0f);
//  }];
}
 
//缩小效果
- (void)collectionview:(uicollectionview *)collectionview didunhighlightitematindexpath:(nsindexpath *)indexpath{
//  customcollectioncell * cell = (customcollectioncell *)[collectionview cellforitematindexpath:indexpath];
//  
//  [uiview animatewithduration:1 animations:^{
//    cell.transform = cgaffinetransformmakescale(1.0f, 1.0f);
//  }];
}
 
 
#pragma mark uicollectionviewdelegateflowlayout
- (cgsize)collectionview:(uicollectionview *)collectionview layout:(uicollectionviewlayout*)collectionviewlayout sizeforitematindexpath:(nsindexpath *)indexpath{
   
  return cgsizemake(100, 100);
}
 
/*
 * 上左下右间距
 */
- (uiedgeinsets)collectionview:(uicollectionview *)collectionview layout:(uicollectionviewlayout*)collectionviewlayout insetforsectionatindex:(nsinteger)section{
   
  return uiedgeinsetsmake(15, 15, 15, 15);
}
 
/*
 * item space
 */
- (cgfloat)collectionview:(uicollectionview *)collectionview layout:(uicollectionviewlayout*)collectionviewlayout minimuminteritemspacingforsectionatindex:(nsinteger)section{
   
  return 8;
}
 
/*
 * 行距 20
 */
- (cgfloat)collectionview:(uicollectionview *)collectionview layout:(uicollectionviewlayout*)collectionviewlayout minimumlinespacingforsectionatindex:(nsinteger)section{
   
  return 10;
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。

原文链接:http://blog.csdn.net/shenjie12345678/article/details/51671713

延伸 · 阅读

精彩推荐
  • IOS关于iOS自适应cell行高的那些事儿

    关于iOS自适应cell行高的那些事儿

    这篇文章主要给大家介绍了关于iOS自适应cell行高的那些事儿,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的...

    daisy6092021-05-17
  • IOSIOS开发之字典转字符串的实例详解

    IOS开发之字典转字符串的实例详解

    这篇文章主要介绍了IOS开发之字典转字符串的实例详解的相关资料,希望通过本文能帮助到大家,让大家掌握这样的方法,需要的朋友可以参考下...

    苦练内功5832021-04-01
  • IOS解析iOS开发中的FirstResponder第一响应对象

    解析iOS开发中的FirstResponder第一响应对象

    这篇文章主要介绍了解析iOS开发中的FirstResponder第一响应对象,包括View的FirstResponder的释放问题,需要的朋友可以参考下...

    一片枫叶4662020-12-25
  • IOSiOS 雷达效果实例详解

    iOS 雷达效果实例详解

    这篇文章主要介绍了iOS 雷达效果实例详解的相关资料,需要的朋友可以参考下...

    SimpleWorld11022021-01-28
  • IOSiOS布局渲染之UIView方法的调用时机详解

    iOS布局渲染之UIView方法的调用时机详解

    在你刚开始开发 iOS 应用时,最难避免或者是调试的就是和布局相关的问题,下面这篇文章主要给大家介绍了关于iOS布局渲染之UIView方法调用时机的相关资料...

    windtersharp7642021-05-04
  • IOSIOS 屏幕适配方案实现缩放window的示例代码

    IOS 屏幕适配方案实现缩放window的示例代码

    这篇文章主要介绍了IOS 屏幕适配方案实现缩放window的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要...

    xiari5772021-06-01
  • IOSiOS通过逆向理解Block的内存模型

    iOS通过逆向理解Block的内存模型

    自从对 iOS 的逆向初窥门径后,我也经常通过它来分析一些比较大的应用,参考一下这些应用中某些功能的实现。这个探索的过程乐趣多多,不仅能满足自...

    Swiftyper12832021-03-03
  • IOSiOS中tableview 两级cell的展开与收回的示例代码

    iOS中tableview 两级cell的展开与收回的示例代码

    本篇文章主要介绍了iOS中tableview 两级cell的展开与收回的示例代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧...

    J_Kang3862021-04-22