UICollectionView——整体总结
前言
這幾天有時間看了下UICollectionView的東西,才發覺它真的非常強大,很有必要好好學習學習。以前雖然用過幾次,但沒有系統的整理總結過。這兩天我為UICollectionView做一個比較全面的整理。包括基本使用,自定義布局,自定義插入刪除動畫,自定義轉場動畫等幾部分。好了,開始。
UICollectionView相對于UITableView可以說是青出于藍而勝于藍,它和UITableView很相似,但它要更加強大。
UITableView的布局形式比較單一,局限于行列表,而UICollectionView的強大之處在于把視圖布局分離出來成為一個獨立的類,你想實現怎樣的視圖布局,就子類化這個類并在其中實現。
UICollectionView基礎
- UICollectionViewFlowLayout:視圖布局對象(流視圖:一行排滿,自動排到下行),繼承自UICollectionViewLayout。
UICollectionViewLayout有個collectionView屬性,
所有的視圖布局對象都繼承自UICollectionViewLayout。若我們要自定義布局對象,我們一般繼承UICollectionViewFlowLayout就可以了。 - 需要實現三個協議;UICollectionViewDataSource(數據源)、UICollectionViewDelegateFlowLayout(視圖布局)、UICollectionViewDelegate。
可以看得出,除了視圖布局,UICollectionView幾乎和UITableView一樣,但這也正是它的強大之處。
1.創建UICollectionView視圖
- (void)loadCollectionView {_customLayout = [[CustomCollectionViewLayout alloc] init]; // 自定義的布局對象_collectionView = [[UICollectionView alloc] initWithFrame:self.view.bounds collectionViewLayout:_customLayout];_collectionView.backgroundColor = [UIColor whiteColor]; _collectionView.dataSource = self; _collectionView.delegate = self; [self.view addSubview:_collectionView]; // 注冊cell、sectionHeader、sectionFooter [_collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:cellId]; [_collectionView registerClass:[UICollectionReusableView class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:headerId]; [_collectionView registerClass:[UICollectionReusableView class] forSupplementaryViewOfKind:UICollectionElementKindSectionFooter withReuseIdentifier:footerId]; }需要注意的是這幾行代碼的位置,及const的位置。(我經常搞亂)
@implementation YWViewController// 注意const的位置 static NSString *const cellId = @"cellId"; static NSString *const headerId = @"headerId"; static NSString *const footerId = @"footerId"; - (void)viewDidLoad {2.實現UICollectionViewDataSource的幾個代理方法
UICollectionView自定義布局
要自定義UICollectionView布局,就要子類化UICollectionViewLayout,然后重寫它的一些方法以達到我們自定義布局的需求。下來我們來看看UICollectionViewLayout類里一些比較重要的方法:
- - (void)prepareLayout;為layout顯示做準備工作,你可以在該方法里設置一些屬性。
- - (CGSize)collectionViewContentSize;返回layout的size。
- - (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect;返回在collectionView的可見范圍內(bounds)所有item對應的layoutAttrure對象裝成的數組。collectionView的每個item都對應一個專門的UICollectionViewLayoutAttributes類型的對象來表示該item的一些屬性,比如bounds,size,transform,alpha等。
- - (UICollectionViewLayoutAttributes )layoutAttributesForItemAtIndexPath:(NSIndexPath )indexPath;傳入indexPath,返回該indexPath對應的layoutAtture對象。
- - (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds; 當當前layout的布局發生變動時,是否重寫加載該layout。默認返回NO,若返回YES,則重新執行這倆方法:
- - (void)prepareLayout;
- - (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect;
- - (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity;返回layout“最終”的偏移量,何謂“最終”,手指離開屏幕時layout的偏移量不是最終的,因為它有慣性,當它停止時才是“最終”偏移量。
下面這兩個方法一般用于自定義插入刪除時的動畫,后面再說。
-
- (UICollectionViewLayoutAttributes )initialLayoutAttributesForAppearingItemAtIndexPath:(NSIndexPath )itemIndexPath;
-
- (nullable UICollectionViewLayoutAttributes )finalLayoutAttributesForDisappearingItemAtIndexPath:(NSIndexPath )itemIndexPath;
本Demo的代碼雖然子類化了UICollectionViewLayout,但是主要是用于自定義插入刪除動畫,所以本段沒什么代碼展示。
UICollectionView插入刪除的操作及動畫
插入刪除的操作
添加在哪觸發:
UIBarButtonItem *btnItem = [[UIBarButtonItem alloc] initWithTitle:@"添加"style:UIBarButtonItemStylePlaintarget:self action:@selector(addItemBtnClick:)]; self.navigationItem.rightBarButtonItem = btnItem;添加的實現:
// 添加(插入item) - (void)addItemBtnClick:(UIBarButtonItem *)btnItem {[_collectionView performBatchUpdates:^{// 構造一個indexPath NSIndexPath *indePath = [NSIndexPath indexPathForItem:_section0Array.count inSection:0]; [_collectionView insertItemsAtIndexPaths:@[indePath]]; // 然后在此indexPath處插入給collectionView插入一個item [_section0Array addObject:@"x"]; // 保持collectionView的item和數據源一致 } completion:nil]; }因為是練習Demo,所以暫時把刪除的觸發源寫在了長按某Item彈出菜單的copy按鈕里。實際中你可以自定義UICollectionViewCell,添加長按手勢,長按抖動出現叉號,然后刪除等,隨你怎么做。
// copy and paste 的實現 - (void)collectionView:(UICollectionView *)collectionView performAction:(SEL)action forItemAtIndexPath:(NSIndexPath *)indexPath withSender:(nullable id)sender { if([NSStringFromSelector(action) isEqualToString:@"copy:"]) { // NSLog(@"-------------執行拷貝-------------"); [_collectionView performBatchUpdates:^{ [_section0Array removeObjectAtIndex:indexPath.row]; [_collectionView deleteItemsAtIndexPaths:@[indexPath]]; } completion:nil]; } else if([NSStringFromSelector(action) isEqualToString:@"paste:"]) { NSLog(@"-------------執行粘貼-------------"); } }插入刪除的動畫
上面已經提到了在UICollectionViewLayout類中有兩個用于自定義動畫的方法,兩個方法分別表示動畫的起始狀態和終止狀態,我們可以分別在方法里設置layoutAttrure來實現某種動畫效果。
蘋果選擇了一種安全的途徑去實現一個簡單的淡入淡出動畫作為所有布局的默認動畫。如果你想實現自定義動畫,最好的辦法是子類化 UICollectionViewFlowLayout 并且在適當的地方實現你的動畫。
一般來說,我們對布局屬性從初始狀態到結束狀態進行線性插值來計算 collection view 的動畫參數。然而,新插入或者刪除的元素并沒有最初或最終狀態來進行插值。要計算這樣的 cells 的動畫,collection view 將通過 initialLayoutAttributesForAppearingItemAtIndexPath: 以及 finalLayoutAttributesForDisappearingItemAtIndexPath: 方法來詢問其布局對象,以獲取最初的和最后的屬性。蘋果默認的實現中,對于特定的某個 indexPath,返回的是它的通常的位置,但 alpha 值為 0.0,這就產生了一個淡入或淡出動畫。
簡而言之,就是蘋果自帶了插入刪除時Item的淡入淡出的動畫,若你想自定義更炫的動畫,就子類化UICollectionViewFlowLayout類,并重寫以下兩個方法:
// 初始狀態 - (nullable UICollectionViewLayoutAttributes *)initialLayoutAttributesForAppearingItemAtIndexPath:(NSIndexPath *)itemIndexPath {UICollectionViewLayoutAttributes *attr = [self layoutAttributesForItemAtIndexPath:itemIndexPath]; attr.center = CGPointMake(CGRectGetMidX(self.collectionView.bounds), CGRectGetMaxY(self.collectionView.bounds)); attr.transform = CGAffineTransformRotate(CGAffineTransformMakeScale(0.2, 0.2), M_PI); return attr; } // 終結狀態 - (nullable UICollectionViewLayoutAttributes *)finalLayoutAttributesForDisappearingItemAtIndexPath:(NSIndexPath *)itemIndexPath { UICollectionViewLayoutAttributes *attr = [self layoutAttributesForItemAtIndexPath:itemIndexPath]; attr.alpha = 0.0f; return attr; }insert&delete.gif
UICollectionView的轉場動畫
http://objccn.io/issue-12-5/
轉載于:https://www.cnblogs.com/Free-Thinker/p/6737701.html
總結
以上是生活随笔為你收集整理的UICollectionView——整体总结的全部內容,希望文章能夠幫你解決所遇到的問題。