ios的collection控件的自定义布局实现与设计

时间:2022-09-18 10:47:44

collection控件用来实现界面的各种自定义布局,最常用其作为横向、竖向的布局控件。很早之前,系统对于collection的支持并不是很好。所以自己实现了支持自定义布局、自定义cell的collection控件。自定义的collection可以满足所有的产品特殊需求及动态效果,例如在某些特殊情况下可能需要除选中cell之外的其它cell执行布局动画等。在collection的基础之上,我又实现了支持cell拖动、拖离窗体的tabview控件。本文主要介绍自定义collection的设计与实现,后续持续更新多tab的tabview控件。

我有几张阿里云幸运券分享给你,用券购买或者升级阿里云相应产品会有特惠惊喜哦!把想要买的产品的幸运券都领走吧!快下手,马上就要抢光了。

产品中的一些实现效果

ios的collection控件的自定义布局实现与设计

mac旺旺表情面板,实现grid与横向布局

ios的collection控件的自定义布局实现与设计

mac千牛工作台用作横向布局

ios的collection控件的自定义布局实现与设计

ios千牛历史登录页面实现当前选中cell变大并且选中cell总中最中位置校准动效的效果

collection

collection主要包括:继承scrollview的collectionview,数据源协议collectionviewdatasource,事件响应协议collectoinviewdelegate,布局基类collectoinlayout以及展示单元collectioncellview。

模块图如下:

ios的collection控件的自定义布局实现与设计

 collectionview

collection容器包含指实现collectionviewdatasource、collectoinviewdelegate协议的指针以及collectoinlayout成员,同时维护collectoincellview的控件重用。

?
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
@interface wwcollectionview : nsscrollview
// 布局对象
@property (retain) wwcollectionviewlayout *layout;
// 数据源
@property (weak) id datasource;
// 事件响应
@property (weak) id delegate;
// 重加载数据
(void)reloaddata;
// 重排布
(void)invalidatelayout;
// 取消返回选中
(void)unselectedall;
// 注册重用对象
(void)registerclass:(class)cellclass forcellwithreuseidentifier:(nsstring *)identifier;
// 对象重用
(id)dequeuereusablecellwithreuseidentifier:(nsstring )identifier forindexpath:(nsindexpath )indexpath;
// 设置选中对象
(void)selectitematindexpath:(nsindexpath *)indexpath animated:(bool)animated;
// 当前选中对象
(nsindexpath *)selecteditem;
// 重加载indexpath item
(void)reloaditemsatindexpath:(nsindexpath *)indexpath;
// 插入
(void)insertitemsatindexpath:(nsindexpath *)indexpath withanimate:(bool)animate;
// 删除
(void)deleteitemsatindexpath:(nsindexpath *)indexpath withanimate:(bool)animate;
// 重新排列
(void)relayoutwithanimation:(bool)animated completion:(void (^)(bool finished))completion;
// 滚动到apoint
(void)scrolltopoint:(nspoint)apoint withanimate:(bool)animate;
@end

collectionviewdatasource

collection展示的数据源,由宿主实现。

?
1
2
3
4
5
6
7
8
@protocol wwcollectionviewdatasource
// 返回indexpath下标的cell
(wwcollectioncellview )collectview:(wwcollectionview )collectionview cellforitematindexpath:(nsindexpath *)indexpath;
// 总cell个数
(nsinteger)numberofitemincollectionview:(wwcollectionview *)collectionview;
// cell的数据
(id)collectionview:(wwcollectionview )colletionview objectvalueatindexpath:(nsindexpath )indexpath;
@end

collectoinviewdelegate

collection事件的回调响应,由宿主实现。

?
1
2
3
4
5
6
@protocol wwcollectionviewdelegate
// indexpath元素被选中
(void)collectionview:(wwcollectionview )collectionview didselectitematindexpath:(nsindexpath )indexpath;
// 是否支持选中
(bool)collectionview:(wwcollectionview )collectionview shouldselectitemsatindexpaths:(nsindexpath )indexpath;
@end

collectoinlayout

collectioncellview的布局方案。

?
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
@interface wwcollectionviewlayout : nsobject
// 布局基类
@property (weak) wwcollectionview *collectionview;
// 每个cell元素大小
@property (assign) nssize itemsize;
// edgeinsets
@property (assign) nsedgeinsets edgeinsets;
// scrollview使用,表示整个画布大小
@property (assign) nssize viewcontentsize;
(instancetype)initwithcollectionview:(wwcollectionview *)collectionview;
(void)invalidatelayout;
// 返回index的cell大小
(nsrect)frameforindexpath:(nsindexpath *)index total:(nsinteger)total;
(nssize)collectionviewcontentsize;
@end
// 横向布局控件
@interface wwflowcollectionviewlayout : wwcollectionviewlayout
@property (assign) cgfloat headmargin;
@property (assign) cgfloat tailmargin;
@end
// grid布局控件
@interface wwgridcollectionviewlayout : wwcollectionviewlayout
// 每行多少个
@property (assign) nsinteger numberperrow;
@property (assign) cgfloat headmargin;
@property (assign) cgfloat tailmargin;
@end
?
1
@implementation wwflowcollectionviewlayout
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
(void)invalidatelayout {
nsinteger cellcount = [self.collectionview.datasource numberofitemincollectionview:self.collectionview];
cgrect bounds = self.collectionview.bounds;
// 画布宽度
cgfloat width = _headmargin + _tailmargin + (cellcount - 1) (self.edgeinsets.left + self.edgeinsets.right) + self.itemsize.width cellcount;
if (width < bounds.size.width) {
width = bounds.size.width;
}
self.viewcontentsize = nsmakesize(width, bounds.size.height);
[super invalidatelayout];
}
(nsrect)frameforindexpath:(nsindexpath *)index total:(nsinteger)total {
cgfloat leftpos = self.headmargin + [index indexatposition:0] * (self.itemsize.width + self.edgeinsets.left + self.edgeinsets.right);
// 返回cell的rect
return nsmakerect(leftpos, self.edgeinsets.top, self.itemsize.width, self.itemsize.height);
}
@end

collectoincellview

collection展示的cell控件。

?
1
2
3
4
5
6
7
8
@interface wwcollectioncellview : nsview
// 当前cell被选中
@property (nonatomic, assign) bool selected;
// 数据
@property (nonatomic, retain) id datavalue;
// 使用前重置展示效果
(void)reset;
@end

原文链接:http://blog.csdn.net/qq_36510261/article/details/78741030