標籤:
iOS流布局UICollectionView系列一——初識與簡單使用UICollectionView 一、簡介
UICollectionView是iOS6之後引入的一個新的UI控制項,它和UITableView有著諸多的相似之處,其中許多代理方法都十分類似。簡單來說,UICollectionView是比UITbleView更加強大的一個UI控制項,有如下幾個方面:
1、支援水平和垂直兩種方向的布局
2、通過layout配置方式進行布局
3、類似於TableView中的cell特性外,CollectionView中的Item大小和位置可以自由定義
4、通過layout布局回調的代理方法,可以動態定製每個item的大小和collection的答題布局屬性
5、更加強大一點,完全自訂一套layout布局方案,可以實現意想不到的效果
這篇部落格,我們主要討論CollectionView使用原生layout的方法和相關屬性,其他特點和更強的制定化,會在後面的部落格中介紹
二、先來實現一個最簡單的九宮格類布局
在瞭解UICollectionView的更多屬性前,我們先來使用其進行一個最簡單的流布局試試看,在controller的viewDidLoad中添加如下代碼:
//建立一個layout布局類 UICollectionViewFlowLayout * layout = [[UICollectionViewFlowLayout alloc]init]; //設定布局方向為垂直流布局 layout.scrollDirection = UICollectionViewScrollDirectionVertical; //設定每個item的大小為100*100 layout.itemSize = CGSizeMake(100, 100); //建立collectionView 通過一個布局策略layout來建立 UICollectionView * collect = [[UICollectionView alloc]initWithFrame:self.view.frame collectionViewLayout:layout]; //代理設定 collect.delegate=self; collect.dataSource=self; //註冊item類型 這裡使用系統的類型 [collect registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:@"cellid"]; [self.view addSubview:collect];
這裡有一點需要注意,collectionView在完成代理回調前,必須註冊一個cell,類似如下:
[collect registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:@"cellid"];
這和tableView有些類似,又有些不同,因為tableView除了註冊cell的方法外,還可以通過臨時建立來做:
//tableView在從複用池中取cell的時候,有如下兩種方法//使用這種方式如果複用池中無,是可以返回nil的,我們在臨時建立即可- (nullable __kindof UITableViewCell *)dequeueReusableCellWithIdentifier:(NSString *)identifier;//6.0後使用如下的方法直接從註冊的cell類擷取建立,如果沒有註冊 會崩潰- (__kindof UITableViewCell *)dequeueReusableCellWithIdentifier:(NSString *)identifier forIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(6_0);
我們可以分析:因為UICollectionView是iOS6.0之前的新類,因此這裡統一了從複用池中擷取cell的方法,沒有再提供可以返回nil的方式,並且在UICollectionView的回調代理中,只能使用從複用池中擷取cell的方式進行cell的返回,其他方式會崩潰,例如:
//這是正確的方法-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{ UICollectionViewCell * cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"cellid" forIndexPath:indexPath]; cell.backgroundColor = [UIColor colorWithRed:arc4random()%255/255.0 green:arc4random()%255/255.0 blue:arc4random()%255/255.0 alpha:1]; return cell;}//這樣做會崩潰-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{// UICollectionViewCell * cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"cellid" forIndexPath:indexPath];// cell.backgroundColor = [UIColor colorWithRed:arc4random()%255/255.0 green:arc4random()%255/255.0 blue:arc4random()%255/255.0 alpha:1]; UICollectionViewCell * cell = [[UICollectionViewCell alloc]init]; return cell;}
上面錯誤的方式會崩潰,資訊如下,讓我們使用從複用池中取cell的方式:
上面的設定完成後,我們來實現如下幾個代理方法:
這裡與TableView的回調方式十分類似
//返回分區個數-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView{ return 1;}//返回每個分區的item個數-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{ return 10;}//返回每個item-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{ UICollectionViewCell * cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"cellid" forIndexPath:indexPath]; cell.backgroundColor = [UIColor colorWithRed:arc4random()%255/255.0 green:arc4random()%255/255.0 blue:arc4random()%255/255.0 alpha:1]; return cell;}
效果如下:
同樣,如果內容的大小超出一屏,和tableView類似是可以進行視圖滑動的。
還有一點細節,我們在上面設定布局方式的時候設定了垂直布局:
layout.scrollDirection = UICollectionViewScrollDirectionVertical;//這個是水平布局//layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
這樣系統會在一行充滿後進行第二行的排列,如果設定為水平布局,則會在一列充滿後,進行第二列的布局,這種方式也被稱為流式布局
三、UICollectionView中的常用方法和屬性
//通過一個布局策略初識化CollectionView- (instancetype)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout;//擷取和設定collection的layout@property (nonatomic, strong) UICollectionViewLayout *collectionViewLayout;//資料來源和代理@property (nonatomic, weak, nullable) id <UICollectionViewDelegate> delegate;@property (nonatomic, weak, nullable) id <UICollectionViewDataSource> dataSource;//從一個class或者xib檔案進行cell(item)的註冊- (void)registerClass:(nullable Class)cellClass forCellWithReuseIdentifier:(NSString *)identifier;- (void)registerNib:(nullable UINib *)nib forCellWithReuseIdentifier:(NSString *)identifier;//下面兩個方法與上面相似,這裡註冊的是頭視圖或者尾視圖的類//其中第二個參數是設定 頭視圖或者尾視圖 系統為我們定義好了這兩個字串//UIKIT_EXTERN NSString *const UICollectionElementKindSectionHeader NS_AVAILABLE_IOS(6_0);//UIKIT_EXTERN NSString *const UICollectionElementKindSectionFooter NS_AVAILABLE_IOS(6_0);- (void)registerClass:(nullable Class)viewClass forSupplementaryViewOfKind:(NSString *)elementKind withReuseIdentifier:(NSString *)identifier;- (void)registerNib:(nullable UINib *)nib forSupplementaryViewOfKind:(NSString *)kind withReuseIdentifier:(NSString *)identifier;//這兩個方法是從複用池中取出cell或者頭尾視圖- (__kindof UICollectionViewCell *)dequeueReusableCellWithReuseIdentifier:(NSString *)identifier forIndexPath:(NSIndexPath *)indexPath;- (__kindof UICollectionReusableView *)dequeueReusableSupplementaryViewOfKind:(NSString *)elementKind withReuseIdentifier:(NSString *)identifier forIndexPath:(NSIndexPath *)indexPath;//設定是否允許選中 預設yes@property (nonatomic) BOOL allowsSelection;//設定是否允許多選 預設no@property (nonatomic) BOOL allowsMultipleSelection;//擷取所有選中的item的位置資訊- (nullable NSArray<NSIndexPath *> *)indexPathsForSelectedItems; //設定選中某一item,並使視圖滑動到相應位置,scrollPosition是滑動位置的相關參數,如下:/*typedef NS_OPTIONS(NSUInteger, UICollectionViewScrollPosition) { //無 UICollectionViewScrollPositionNone = 0, //垂直布局時使用的 對應上中下 UICollectionViewScrollPositionTop = 1 << 0, UICollectionViewScrollPositionCenteredVertically = 1 << 1, UICollectionViewScrollPositionBottom = 1 << 2, //水平布局時使用的 對應左中右 UICollectionViewScrollPositionLeft = 1 << 3, UICollectionViewScrollPositionCenteredHorizontally = 1 << 4, UICollectionViewScrollPositionRight = 1 << 5};*/- (void)selectItemAtIndexPath:(nullable NSIndexPath *)indexPath animated:(BOOL)animated scrollPosition:(UICollectionViewScrollPosition)scrollPosition;//將某一item取消選中- (void)deselectItemAtIndexPath:(NSIndexPath *)indexPath animated:(BOOL)animated;//重新載入資料- (void)reloadData;//下面這兩個方法,可以重新設定collection的布局,後面的方法多了一個布局完成後的回調,iOS7後可以用//使用這兩個方法可以產生非常炫酷的動畫效果- (void)setCollectionViewLayout:(UICollectionViewLayout *)layout animated:(BOOL)animated;- (void)setCollectionViewLayout:(UICollectionViewLayout *)layout animated:(BOOL)animated completion:(void (^ __nullable)(BOOL finished))completion NS_AVAILABLE_IOS(7_0);//下面這些方法更加強大,我們可以對布局更改後的動畫進行設定//這個方法傳入一個布局策略layout,系統會開始進行布局渲染,返回一個UICollectionViewTransitionLayout對象//這個UICollectionViewTransitionLayout對象管理動畫的相關屬性,我們可以進行設定- (UICollectionViewTransitionLayout *)startInteractiveTransitionToCollectionViewLayout:(UICollectionViewLayout *)layout completion:(nullable UICollectionViewLayoutInteractiveTransitionCompletion)completion NS_AVAILABLE_IOS(7_0);//準備好動畫設定後,我們需要調用下面的方法進行布局動畫的展示,之後會調用上面方法的block回調- (void)finishInteractiveTransition NS_AVAILABLE_IOS(7_0);//調用這個方法取消上面的布局動畫設定,之後也會進行上面方法的block回調- (void)cancelInteractiveTransition NS_AVAILABLE_IOS(7_0);//擷取分區數- (NSInteger)numberOfSections;//擷取某一分區的item數- (NSInteger)numberOfItemsInSection:(NSInteger)section;//下面兩個方法擷取item或者頭尾視圖的layout屬性,這個UICollectionViewLayoutAttributes對象//存放著布局的相關資料,可以用來做完全自訂布局,後面部落格會介紹- (nullable UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath;- (nullable UICollectionViewLayoutAttributes *)layoutAttributesForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath;//擷取某一點所在的indexpath位置- (nullable NSIndexPath *)indexPathForItemAtPoint:(CGPoint)point;//擷取某個cell所在的indexPath- (nullable NSIndexPath *)indexPathForCell:(UICollectionViewCell *)cell;//根據indexPath擷取cell- (nullable UICollectionViewCell *)cellForItemAtIndexPath:(NSIndexPath *)indexPath;//擷取所有可見cell的數組- (NSArray<__kindof UICollectionViewCell *> *)visibleCells;//擷取所有可見cell的位置數組- (NSArray<NSIndexPath *> *)indexPathsForVisibleItems;//下面三個方法是iOS9中新添加的方法,用於擷取頭尾視圖- (UICollectionReusableView *)supplementaryViewForElementKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(9_0);- (NSArray<UICollectionReusableView *> *)visibleSupplementaryViewsOfKind:(NSString *)elementKind NS_AVAILABLE_IOS(9_0);- (NSArray<NSIndexPath *> *)indexPathsForVisibleSupplementaryElementsOfKind:(NSString *)elementKind NS_AVAILABLE_IOS(9_0);//使視圖滑動到某一位置,可以帶動畫效果- (void)scrollToItemAtIndexPath:(NSIndexPath *)indexPath atScrollPosition:(UICollectionViewScrollPosition)scrollPosition animated:(BOOL)animated;//下面這些方法用於動態添加,刪除,移動某些分區擷取items- (void)insertSections:(NSIndexSet *)sections;- (void)deleteSections:(NSIndexSet *)sections;- (void)reloadSections:(NSIndexSet *)sections;- (void)moveSection:(NSInteger)section toSection:(NSInteger)newSection;- (void)insertItemsAtIndexPaths:(NSArray<NSIndexPath *> *)indexPaths;- (void)deleteItemsAtIndexPaths:(NSArray<NSIndexPath *> *)indexPaths;- (void)reloadItemsAtIndexPaths:(NSArray<NSIndexPath *> *)indexPaths;- (void)moveItemAtIndexPath:(NSIndexPath *)indexPath toIndexPath:(NSIndexPath *)newIndexPath;
iOS流布局UICollectionView系列一——初識與簡單使用UICollectionView