介绍
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