1 定義
1.1 什么是UICollectionView
????????UICollectionView是一種新的數(shù)據(jù)展示方式啦扬,簡單來說可以把他理解成多列的UITableView(請一定注意這是UICollectionView的最最簡單的形式)垒迂。
????????最簡單的UICollectionView就是一個GridView票髓,可以以多列的方式將數(shù)據(jù)進行展示。標準的UICollectionView包含三個部分管行,它們都是UIView的子類:
????? Cells 用于展示內容的主體,對于不同的cell可以指定不同尺寸和不同的內容,這個稍后再說
????? Supplementary Views 追加視圖 如果你對UITableView比較熟悉的話起胰,可以理解為每個Section的Header或者Footer,用來標記每個section的view
????? Decoration Views 裝飾視圖 這是每個section的背景巫延,比如iBooks中的書架就是這個
????????不管一個UICollectionView的布局如何變化效五,這三個部件都是存在的。再次說明炉峰,復雜的UICollectionView絕不止上面的幾幅圖畏妖,關于較復雜的布局和相應的特性,我會在本文稍后和下一篇筆記中進行一些深入疼阔。
1.2 UICollectionViewDataSource
????? section的數(shù)量-numberOfSectionsInCollection:
????? 某個section里有多少個item-collectionView: numberOfItemsInSection:
????? 對于某個位置應該顯示什么樣的cell -collectionView: cellForItemAtIndexPath:
????????實現(xiàn)以上三個委托方法戒劫,基本上就可以保證CollectionView工作正常了。當然婆廊,還有提供Supplementary View的方法迅细。
????? collectionView: viewForSupplementaryElementOfKind: atIndexPath:
????????對于Decoration Views,提供方法并不在UICollectionViewDataSource中淘邻,而是直接在UICollectionViewLayout類中的(因為它僅僅是視圖相關茵典,而與數(shù)據(jù)無關),放到稍后再說宾舅。
1.3 關于重用
????????為了得到高效的View统阿,對于cell的重用是必須的,避免了不斷生成和銷毀對象的操作筹我,這與在UITableView中的情況是一致的扶平。但值得注意的時,在UICollectionView中崎溃,不僅cell可以重用蜻直,Supplementary View和Decoration View也是可以并且應當被重用的。在iOS5中袁串,Apple對UITableView的重用做了簡化概而,以往要寫類似這樣的代碼:
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"MY_CELL_ID"];
//如果沒有可重用的cell,那么生成一個?
if (!cell) {
????cell = [[UITableViewCell alloc] init];
}
//配置cell囱修,blablabla
return cell;
????????而如果我們在TableView向數(shù)據(jù)源請求數(shù)據(jù)之前使用-registerNib:forCellReuseIdentifier:方法為@“MY_CELL_ID”注冊過nib的話赎瑰,就可以省下每次判斷并初始化cell的代碼,要是在重用隊列里沒有可用的cell的話破镰,runtime將自動幫我們生成并初始化一個可用的cell餐曼。
????????這個特性很受歡迎压储,因此在UICollectionView中Apple繼承使用了這個特性,并且把其進行了一些擴展源譬。使用以下方法進行注冊:
????? -registerClass: forCellWithReuseIdentifier:
????? -registerClass: forSupplementaryViewOfKind: withReuseIdentifier:
????? -registerNib: forCellWithReuseIdentifier:
????? -registerNib: forSupplementaryViewOfKind: withReuseIdentifier:
????????相比UITableView有兩個主要變化:一是加入了對某個Class的注冊集惋,這樣即使不用提供nib而是用代碼生成的view也可以被接受為cell了;二是不僅只是cell踩娘,Supplementary View也可以用注冊的方法綁定初始化了刮刑。在對collection view的重用ID注冊后,就可以像UITableView那樣簡單的寫cell配置了:
????MyCell*cell=[cvdequeueReusableCellWithReuseIdentifier:@”MY_CELL_ID”];
????// Configure the cell's content
????cell.imageView.image=...
????return cell;
}
????????需要吐槽的是养渴,對collection view雷绢,取重用隊列的方法的名字和UITableView里面不一樣了,在Identifier前面多加了Reuse五個字母理卑,語義上要比以前清晰翘紊,命名規(guī)則也比以前嚴謹了。
1.4 UICollectionViewDelegate
????????數(shù)據(jù)無關的view的外形啊藐唠,用戶交互啊什么的帆疟,由UICollectionViewDelegate來負責:
????? cell的高亮
????? cell的選中狀態(tài)
????? 可以支持長按后的菜單
????????關于用戶交互,UICollectionView也做了改進中捆。每個cell現(xiàn)在有獨立的高亮事件和選中事件的delegate鸯匹,用戶點擊cell的時候,現(xiàn)在會按照以下流程向delegate進行詢問:
????? -collectionView: shouldHighlightItemAtIndexPath: 是否應該高亮泄伪?
????? -collectionView: didHighlightItemAtIndexPath: 如果1回答為是殴蓬,那么高亮
????? -collectionView: shouldSelectItemAtIndexPath: 無論1結果如何,都詢問是否可以被選中蟋滴?
????? -collectionView: didUnhighlightItemAtIndexPath: 如果1回答為是染厅,那么現(xiàn)在取消高亮
????? -collectionView: didSelectItemAtIndexPath: 如果3回答為是,那么選中cell
????????狀態(tài)控制要比以前靈活一些津函,對應的高亮和選中狀態(tài)分別由highlighted和selected兩個屬性表示肖粮。
1.5 關于Cell
????????相對于UITableViewCell來說,UICollectionViewCell沒有這么多花頭尔苦。首先UICollectionViewCell不存在各式各樣的默認的style汤锨,這主要是由于展示對象的性質決定的咱旱,因為UICollectionView所用來展示的對象相比UITableView來說要來得靈活镣隶,大部分情況下更偏向于圖像而非文字隙笆,因此需求將會千奇百怪。因此SDK提供給我們的默認的UICollectionViewCell結構上相對比較簡單稠项,由下至上:
????? 首先是cell本身作為容器view
????? 然后是一個大小自動適應整個cell的backgroundView涯雅,用作cell平時的背景
????? 再其上是selectedBackgroundView,是cell被選中時的背景
????? 最后是一個contentView展运,自定義內容應被加在這個view上
????????這次Apple給我們帶來的好康是被選中cell的自動變化活逆,所有的cell中的子view精刷,也包括contentView中的子view,在當cell被選中時蔗候,會自動去查找view是否有被選中狀態(tài)下的改變怒允。比如在contentView里加了一個normal和selected指定了不同圖片的imageView,那么選中這個cell的同時這張圖片也會從normal變成selected琴庵,而不需要額外的任何代碼误算。
1.6 UICollectionViewLayout
????????這是UICollectionView和UITableView最大的不同。UICollectionViewLayout可以說是UICollectionView的大腦和中樞迷殿,它負責了將各個cell、Supplementary View和Decoration Views進行組織咖杂,為它們設定各自的屬性庆寺,包括但不限于:
????? 位置
????? 尺寸
????? 透明度
????? 層級關系
????? 形狀
????? 等等等等…
????????Layout決定了UICollectionView是如何顯示在界面上的。在展示之前诉字,一般需要生成合適的UICollectionViewLayout子類對象懦尝,并將其賦予CollectionView的collectionViewLayout屬性。關于詳細的自定義UICollectionViewLayout和一些細節(jié)壤圃,我將寫在之后一篇筆記中陵霉。
????????Apple為我們提供了一個最簡單可能也是最常用的默認layout對象,UICollectionViewFlowLayout伍绳。Flow Layout簡單說是一個直線對齊的layout踊挠,最常見的Grid View形式即為一種Flow Layout配置。上面的照片架界面就是一個典型的Flow Layout冲杀。
????? 首先一個重要的屬性是itemSize效床,它定義了每一個item的大小。通過設定itemSize可以全局地改變所有cell的尺寸权谁,如果想要對某個cell制定尺寸剩檀,可以使用-collectionView: layout: sizeForItemAtIndexPath:方法。
? ? ? 間隔 可以指定item之間的間隔和每一行之間的間隔旺芽,和size類似沪猴,有全局屬性,也可以對每一個item和每一個section做出設定:
@property (CGSize) minimumInteritemSpacing
@property (CGSize) minimumLineSpacing
-collectionView: layout: minimumInteritemSpacingForSectionAtIndex:
-collectionView: layout: minimumLineSpacingForSectionAtIndex:
????? 滾動方向 由屬性scrollDirection確定scroll view的方向采章,將影響Flow Layout的基本方向和由header及footer確定的section之間的寬度
????????UICollectionViewScrollDirectionVertical
????????UICollectionViewScrollDirectionHorizontal
????? Header和Footer尺寸 同樣地分為全局和部分运嗜。需要注意根據(jù)滾動方向不同,header和footer的高和寬中只有一個會起作用共缕。垂直滾動時section間寬度為該尺寸的高洗出,而水平滾動時為寬度起作用,如圖图谷。
????@property (CGSize) headerReferenceSize
????@property (CGSize) footerReferenceSize
????- collectionView: layout: referenceSizeForHeaderInSection:
????- collectionView: layout: referenceSizeForFooterInSection:
????? 縮進
????@property UIEdgeInsets sectionInset;
????- collectionView: layout: insetForSectionAtIndex:
1.7 總結
????????一個UICollectionView的實現(xiàn)包括兩個必要部分:UICollectionViewDataSource和UICollectionViewLayout翩活,和一個交互部分:UICollectionViewDelegate阱洪。而Apple給出的UICollectionViewFlowLayout已經(jīng)是一個很強力的layout方案了。
2 實現(xiàn)
2.1 UICollectionView實例的代碼初始化化
????NSUInteger collectionViewHeight = (_myCellVMArray.count + 2)/3 * kMyInfoCollectionCellHeight + 10;
??? //確定是水平滾動菠镇,還是垂直滾動
??? UICollectionViewFlowLayout *flowLayout=[[UICollectionViewFlowLayout alloc] init];
??? [flowLayout setScrollDirection: UICollectionViewScrollDirectionVertical];
??? _myCollectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(0, _myAccView.frame.origin.y + _myAccView.frame.size.height, self.view.frame.size.width, collectionViewHeight) collectionViewLayout: flowLayout];
??? _myCollectionView.delegate = self;
??? _myCollectionView.dataSource = self;
??? [_myCollectionView registerClass: [HJMyInfoCollectionCell class] forCellWithReuseIdentifier: kMyCollectionCellIdentifier];
??? [self.view addSubview: _myCollectionView];
2.2 UICollectionView加載過程
????????總的加載過程是先加載UICollectionView的委托回調配置冗荸,再初始化UICollectionViewCell。
????1利耍、設置numberOfSectionsInCollectionView蚌本;
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView*)collectionView
{
??? return 1;
}
????2、設置numberOfItemsInSection隘梨;
- (NSInteger) collectionView: (UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
??? return [_myCellVMArray count];
}
????3程癌、設置sizeForItemAtIndexPath;
//定義每個UICollectionViewCell 的大小
- (CGSize) collectionView: (UICollectionView *)collectionView layout: (UICollectionViewLayout*) collectionViewLayout sizeForItemAtIndexPath: (NSIndexPath*)indexPath
{
??? NSInteger width = kCollectionViewCellWidth;
??? return CGSizeMake(width , kInfoCollectionCellHeight);
}
????4轴猎、設置insetForSectionAtIndex嵌莉;
//定義每個UICollectionViewCell 的margin
-(UIEdgeInsets) collectionView: (UICollectionView *)collectionView layout: (UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex: (NSInteger)section
{
??? return UIEdgeInsetsMake(2, 2, 2, 2);
}
????5、配置cellForItemAtIndexPath
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath*)indexPath
{
? ? HJInfoCollectionCell *cell= (HJInfoCollectionCell *)[_myInfoCollectionView dequeueReusableCellWithReuseIdentifier: kInfoCollectionCellIdentifier forIndexPath: indexPath];
??? if(!cell) {
??????? cell = [[HJInfoCollectionCell alloc] initWithFrame:CGRectMake(0, 0, kInfoCollectionViewCellWidth, kInfoCollectionCellHeight)];
??? }
??? cell.infoVM = [_myAccCellVMArray objectAtIndex: indexPath.row];
??? return cell;
}
2.3 UICollectionViewCell重用
????????UICollectionViewCell其實只實例化了能應付一屏顯示范圍的對象實例捻脖,而在cellForItemAtIndexPath方法中重復更新此實例的業(yè)務數(shù)據(jù)來達到顯示不同Cell的目的锐峭。
????????UICollectionViewCell的實例化是通過dequeueReusableCellWithReuseIdentifier來實現(xiàn),代碼示例如下:
HJInfoCollectionCell *cell= (HJInfoCollectionCell *) [_myInfoCollectionView dequeueReusableCellWithReuseIdentifier: kInfoCollectionCellIdentifier forIndexPath: indexPath];
????????在dequeueReusableCell方法中可婶,程序會調用Cell的- (instancetype) initWithFrame:(CGRect)frame實現(xiàn)對象的實例化沿癞。因此自定義Cell的初始化方法實現(xiàn)- (instancetype)initWithFrame:(CGRect)frame就可以了,而不用像筆者一樣去畫蛇添足地實現(xiàn)一個-(instancetype) initWithFrame: (CGRect) frame WithVM:(HJInfoCellVM *) vm方法矛渴,后面這個方法永遠也調用不到椎扬。
? ? ? ? 而對于業(yè)務數(shù)據(jù)的綁定與頁面控件更新邏輯,筆者建議在對應業(yè)務對象的Set方法中實現(xiàn)曙旭,例如上面的HJInfoCellVM業(yè)務對象盗舰,就在其Set方法中實現(xiàn)就可以了,示例如下:
- (void)setInfoVM: (HJInfoCellVM*)infoVM
{
??? _infoVM= infoVM;
??? [self reloadSubViews];
}
3 開發(fā)技巧
3.1 布局技巧
3.1.1 設置每一行顯示cell個數(shù)
????????需要用到UICollectionViewFlowLayout:
HJCollectionViewEqualWidthFlowLayout *flowLayout = [[HJCollectionViewEqualWidthFlowLayout alloc] initWithItemCountPerRow: kShareItemCountPerRow withItemSize: itemSize];
???flowLayout.maximumSpacing = 1;
???flowLayout.minimumLineSpacing = 1;
???flowLayout.minimumInteritemSpacing = 1;
??? _collectionView.collectionViewLayout = flowLayout;
3.1.2 單元格等間距實現(xiàn)
??? 繼承并自定義實現(xiàn)layoutAttributesForElementsInRect方法
@interface HJCollectionViewEqualWidthFlowLayout : UICollectionViewFlowLayout
@property (nonatomic) floatmaximumSpacing;
- (instancetype) initWithItemCountPerRow: (NSInteger) count WithItemSize: (CGSize) size;
-(void) setItemCountPerRow: (NSInteger) count;
@end
-(NSArray*) layoutAttributesForElementsInRect: (CGRect)rect
{
??? NSMutableArray* attributes = [[super layoutAttributesForElementsInRect: rect] mutableCopy];
??? for (UICollectionViewLayoutAttributes *attr in attributes) {
??????? NSLog(@"%@", NSStringFromCGRect([attr frame]));
??? }
??? int j = 0, k= 0;
??? //我們想設置的最大間距桂躏,可根據(jù)需要改
??? NSInteger maximumSpacing = _maximumSpacing;
??? for(int i = 0; i < [attributes count]; ++i) {
??????? //當前attributes
??????? UICollectionViewLayoutAttributes *currentLayoutAttributes = attributes[i];
??????? k = i %_itemCountPerRow;
??????? j = i /_itemCountPerRow;
??????? CGRect frame = currentLayoutAttributes.frame;
??????? frame.origin.x = k * (self.itemSize.width+ maximumSpacing);
??????? frame.origin.y = j * (self.itemSize.height+ maximumSpacing);
??????? currentLayoutAttributes.frame= frame;
??? }
??? return attributes;
}
3.1.3 單元格間隔線
????????自定義Cell钻趋,將ContentView的Frame設置稍小
- (void) initSubViews
{
??? self.contentView.frame = CGRectMake(0, 0, self.frame.size.width - 1, self.frame.size.height - 1);
??? self.backgroundColor = [UIColor colorWithRed: 224.0/255 green: 224.0/255 blue: 224.0/255 alpha:1.0];
??? _infoImageView = [[UIImageView alloc] initWithFrame: CGRectMake(0, 0, self.contentView.frame.size.width, self.contentView.frame.size.height)];
??? [self.contentView addSubview: _infoImageView];
}
3.1.4 ItemSize設置錯誤導致單元格加載不完全問題
CGSize itemSize = CGSizeMake([UIScreen mainScreen].bounds.size.width / 2.0-0.5, kProductListCellHeight - 1);
_flowLayout = [[HJCollectionViewEqualWidthFlowLayout alloc] initWithItemCountPerRow: kRow WithItemSize: itemSize];
_flowLayout.maximumSpacing = 1;
_flowLayout.minimumLineSpacing = 1;
_flowLayout.minimumInteritemSpacing = 1;
_collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout: _flowLayout];
要點1:單元格尺寸計算時要來考慮間隔線寬度的影響;
要點2:minimumLineSpacing與minimumInteritemSpacing屬性必須成對使用剂习;
4 參考鏈接
UICollectionView詳解
http://blog.csdn.net/majiakun1/article/details/17204693
UICollectionView的使用方法及demo
http://www.tuicool.com/articles/QJjeqy
iOS開發(fā)-UICollectionView詳解+實例
http://www.cnblogs.com/ios8/p/iOS-UICollectionView.html
iOS開發(fā) 純代碼創(chuàng)建UICollectionView
http://jingyan.baidu.com/article/eb9f7b6d8a81a5869364e8a6.html
UICollectionView不同大小Cell等間距的實現(xiàn)
http://www.th7.cn/Program/IOS/201505/449935.shtml
UICollectionView cell橫向間距如何調整(列距調整)??
http://www.cocoachina.com/bbs/read.php?tid-245356.html
ios開發(fā)——解決UICollectionView的cell間距與設置不符問題
http://www.bkjia.com/IOSjc/917782.html
UICollectionView使用小結