ios的collection控件的自定义布局实现与设计
collection控件用来实现界面的各种自定义布局,最常用其作为横向、竖向的布局控件。很早之前,系统对于collection的支持并不是很好。所以自己实现了支持自定义布局、自定义cell的collection控件。自定义的collection可以满足所有的产品特殊需求及动态效果,例如在某些特殊情况下可能需要除选中cell之外的其它cell执行布局动画等。在collection的基础之上,我又实现了支持cell拖动、拖离窗体的tabview控件。本文主要介绍自定义collection的设计与实现,后续持续更新多tab的tabview控件。
我有几张阿里云幸运券分享给你,用券购买或者升级阿里云相应产品会有特惠惊喜哦!把想要买的产品的幸运券都领走吧!快下手,马上就要抢光了。
产品中的一些实现效果
mac旺旺表情面板,实现grid与横向布局
mac千牛工作台用作横向布局
ios千牛历史登录页面实现当前选中cell变大并且选中cell总中最中位置校准动效的效果
collection
collection主要包括:继承scrollview的collectionview,数据源协议collectionviewdatasource,事件响应协议collectoinviewdelegate,布局基类collectoinlayout以及展示单元collectioncellview。
模块图如下:
collectionview
collection容器包含指实现collectionviewdatasource、collectoinviewdelegate协议的指针以及collectoinlayout成员,同时维护collectoincellview的控件重用。
@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展示的数据源,由宿主实现。
@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事件的回调响应,由宿主实现。
@protocol wwcollectionviewdelegate // indexpath元素被选中 (void)collectionview:(wwcollectionview )collectionview didselectitematindexpath:(nsindexpath )indexpath; // 是否支持选中 (bool)collectionview:(wwcollectionview )collectionview shouldselectitemsatindexpaths:(nsindexpath )indexpath; @end
collectoinlayout
collectioncellview的布局方案。
@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
@implementation wwflowcollectionviewlayout
(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控件。
@interface wwcollectioncellview : nsview // 当前cell被选中 @property (nonatomic, assign) bool selected; // 数据 @property (nonatomic, retain) id datavalue; // 使用前重置展示效果 (void)reset; @end