[iOS]UICollcetionView 相關(guān)屬性和方法

UICollectionView相對于UITableView可以說是青出于藍(lán)而勝于藍(lán)培己,它和UITableView很相似吭敢,但它要更加強(qiáng)大剪廉。UITableView的布局形式比較單一质帅,局限于行列表,而UICollectionView的強(qiáng)大之處在于把視圖布局分離出來成為一個獨(dú)立的類黔牵,你想實(shí)現(xiàn)怎樣的視圖布局聪轿,就子類化這個類并在其中實(shí)現(xiàn)。
UICollectionView基礎(chǔ)
UICollectionViewFlowLayout:視圖布局對象(流視圖:一行排滿猾浦,自動排到下行)陆错,繼承自UICollectionViewLayout。UICollectionViewLayout有個collectionView屬性金赦,所有的視圖布局對象都繼承自UICollectionViewLayout音瓷。若我們要自定義布局對象,我們一般繼承UICollectionViewFlowLayout就可以了夹抗。
需要實(shí)現(xiàn)三個協(xié)議绳慎;UICollectionViewDataSource(數(shù)據(jù)源)、UICollectionViewDelegateFlowLayout(視圖布局)、UICollectionViewDelegate偷线∧ト罚可以看得出,除了視圖布局声邦,UICollectionView幾乎和UITableView一樣乏奥,但這也正是它的強(qiáng)大之處。

1.創(chuàng)建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的位置媳瞪。(我經(jīng)常搞亂)

@implementation YWViewController// 注意const的位置static NSString *const cellId = @"cellId";static NSString *const headerId = @"headerId";static NSString *const footerId = @"footerId";- (void)viewDidLoad{

2.實(shí)現(xiàn)UICollectionViewDataSource的幾個代理方法

#pragma mark ---- UICollectionViewDataSource
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{ 
      return 1;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
     return _section0Array.count;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
     UICollectionViewCell *cell = [_collectionView dequeueReusableCellWithReuseIdentifier:cellId forIndexPath:indexPath];     
    cell.backgroundColor = [UIColor purpleColor]; return cell;
}
// 和UITableView類似骗炉,UICollectionView也可設(shè)置段頭段尾
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
{
     if([kind isEqualToString:UICollectionElementKindSectionHeader])
       {
         UICollectionReusableView *headerView = [_collectionView dequeueReusableSupplementaryViewOfKind:kind withReuseIdentifier:headerId forIndexPath:indexPath];
         if(headerView == nil) 
        { 
          headerView = [[UICollectionReusableView alloc] init]; 
        }
         headerView.backgroundColor = [UIColor grayColor]; 
          return headerView;
         } else if([kind isEqualToString:UICollectionElementKindSectionFooter])
         {
                 UICollectionReusableView *footerView = [_collectionView dequeueReusableSupplementaryViewOfKind:kind withReuseIdentifier:footerId forIndexPath:indexPath]; 
              if(footerView == nil) 
             {
                 footerView = [[UICollectionReusableView alloc] init]; 
            }
           footerView.backgroundColor = [UIColor lightGrayColor];
           return footerView; 
            } 
            return nil;
 }
- (BOOL)collectionView:(UICollectionView *)collectionView canMoveItemAtIndexPath:(NSIndexPath *)indexPath
{
       return YES;
}
- (void)collectionView:(UICollectionView *)collectionView moveItemAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath*)destinationIndexPath
{

}
#pragma mark ---- UICollectionViewDelegateFlowLayout
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
 return (CGSize){cellWidth,cellWidth};
}
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section
{
 return UIEdgeInsetsMake(5, 5, 5, 5);
}
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section
{
 return 5.f;
}
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section
{
 return 5.f;
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section
{
 return (CGSize){ScreenWidth,44};
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout referenceSizeForFooterInSection:(NSInteger)section
{
 return (CGSize){ScreenWidth,22};
}
#pragma mark ---- UICollectionViewDelegate
- (BOOL)collectionView:(UICollectionView *)collectionView shouldHighlightItemAtIndexPath:(NSIndexPath *)indexPath
{
 return YES;
}
// 點(diǎn)擊高亮
- (void)collectionView:(UICollectionView *)collectionView didHighlightItemAtIndexPath:(NSIndexPath *)indexPath
{
 UICollectionViewCell *cell = [collectionView cellForItemAtIndexPath:indexPath]; 
cell.backgroundColor = [UIColor greenColor];
}
// 選中某item
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
}
// 長按某item,彈出copy和paste的菜單
- (BOOL)collectionView:(UICollectionView *)collectionView shouldShowMenuForItemAtIndexPath:(NSIndexPath *)indexPath
{
 return YES;
}
// 使copy和paste有效- (BOOL)collectionView:(UICollectionView *)collectionView canPerformAction:(SEL)action forItemAtIndexPath:(NSIndexPath *)indexPath withSender:(nullable id)sender
{
   if ([NSStringFromSelector(action) isEqualToString:@"copy:"] ||      [NSStringFromSelector(action) isEqualToString:@"paste:"]) 
   {
   return YES;
   }
 return NO;
}
//
- (void)collectionView:(UICollectionView *)collectionView performAction:(SEL)action forItemAtIndexPath:(NSIndexPath *)indexPath withSender:(nullable id)sender
{
 if([NSStringFromSelector(action) isEqualToString:@"copy:"])
 {
// NSLog(@"-------------執(zhí)行拷貝-------------"); 
[_collectionView performBatchUpdates:^{ [_section0Array removeObjectAtIndex:indexPath.row];
 [_collectionView deleteItemsAtIndexPaths:@[indexPath]];} completion:nil];
 } 
else if([NSStringFromSelector(action) isEqualToString:@"paste:"])
   {
 NSLog(@"-------------執(zhí)行粘貼-------------"); 
  }
}

UICollectionView自定義布局

要自定義UICollectionView布局蛇受,就要子類化UICollectionViewLayout句葵,然后重寫它的一些方法以達(dá)到我們自定義布局的需求。下來我們來看看UICollectionViewLayout類里一些比較重要的方法:

- (void)prepareLayout;為layout顯示做準(zhǔn)備工作兢仰,你可以在該方法里設(shè)置一些屬性乍丈。

- (CGSize)collectionViewContentSize;返回layout的size。

*- (NSArray )layoutAttributesForElementsInRect:(CGRect)rect;返回在
collectionView的可見范圍內(nèi)(bounds)所有item對應(yīng)的layoutAttrure對象裝成的數(shù)組把将。collectionView的每個item都對應(yīng)一個專門的UICollectionViewLayoutAttributes類型的對象來表示該item的一些屬性轻专,比如bounds,size,transform,alpha等。

**- (UICollectionViewLayoutAttributes )layoutAttributesForItemAtIndexPath:(NSIndexPath )indexPath;傳入indexPath察蹲,返回該indexPath對應(yīng)的layoutAtture對象请垛。

**- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds; **當(dāng)當(dāng)前l(fā)ayout的布局發(fā)生變動時,是否重寫加載該layout洽议。默認(rèn)返回NO宗收,若返回YES,則重新執(zhí)行這倆方法:

  • (void)prepareLayout;
  • (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect;

- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity;返回layout“最終”的偏移量绞铃,何謂“最終”镜雨,手指離開屏幕時layout的偏移量不是最終的,因為它有慣性儿捧,當(dāng)它停止時才是“最終”偏移量。

下面這兩個方法一般用于自定義插入刪除時的動畫挑宠,后面再說菲盾。
**- (UICollectionViewLayoutAttributes )initialLayoutAttributesForAppearingItemAtIndexPath:(NSIndexPath )itemIndexPath;

**- (nullable UICollectionViewLayoutAttributes )finalLayoutAttributesForDisappearingItemAtIndexPath:(NSIndexPath )itemIndexPath;

本Demo的代碼雖然子類化了UICollectionViewLayout,但是主要是用于自定義插入刪除動畫各淀,所以本段沒什么代碼展示懒鉴。

UICollectionView插入刪除的操作及動畫
插入刪除的操作
添加在哪觸發(fā):

UIBarButtonItem *btnItem = [[UIBarButtonItem alloc] initWithTitle:@"添加" style:UIBarButtonItemStylePlain target:self action:@selector(addItemBtnClick:)]; 
self.navigationItem.rightBarButtonItem = btnItem;```

添加的實(shí)現(xiàn):

// 添加(插入item)

  • (void)addItemBtnClick:(UIBarButtonItem *)btnItem
    {
    [_collectionView performBatchUpdates:^{
    // 構(gòu)造一個indexPath
    NSIndexPath *indePath = [NSIndexPath indexPathForItem:_section0Array.count inSection:0];
    [_collectionView insertItemsAtIndexPaths:@[indePath]]; // 然后在此indexPath處插入給collectionView插入一個item
    [_section0Array addObject:@"x"]; // 保持collectionView的item和數(shù)據(jù)源一致
    } completion:nil];
    }```

因為是練習(xí)Demo,所以暫時把刪除的觸發(fā)源寫在了長按某Item彈出菜單的copy按鈕里。實(shí)際中你可以自定義UICollectionViewCell临谱,添加長按手勢璃俗,長按抖動出現(xiàn)叉號,然后刪除等悉默,隨你怎么做城豁。

// copy and paste 的實(shí)現(xiàn)
- (void)collectionView:(UICollectionView *)collectionView performAction:(SEL)action forItemAtIndexPath:(NSIndexPath *)indexPath withSender:(nullable id)sender
{
         if([NSStringFromSelector(action) isEqualToString:@"copy:"]) 
      {
        // NSLog(@"-------------執(zhí)行拷貝-------------");
       [_collectionView performBatchUpdates:^{
         [_section0Array removeObjectAtIndex:indexPath.row];
         [_collectionView deleteItemsAtIndexPaths:@[indexPath]];
       } completion:nil]; 
}
 else if([NSStringFromSelector(action) isEqualToString:@"paste:"])
 {
       NSLog(@"-------------執(zhí)行粘貼-------------"); 
  }
}```

插入刪除的動畫
上面已經(jīng)提到了在UICollectionViewLayout類中有兩個用于自定義動畫的方法,兩個方法分別表示動畫的起始狀態(tài)和終止?fàn)顟B(tài)抄课,我們可以分別在方法里設(shè)置layoutAttrure來實(shí)現(xiàn)某種動畫效果唱星。

蘋果選擇了一種安全的途徑去實(shí)現(xiàn)一個簡單的淡入淡出動畫作為所有布局的默認(rèn)動畫。如果你想實(shí)現(xiàn)自定義動畫跟磨,最好的辦法是子類化 UICollectionViewFlowLayout 并且在適當(dāng)?shù)牡胤綄?shí)現(xiàn)你的動畫间聊。
一般來說,我們對布局屬性從初始狀態(tài)到結(jié)束狀態(tài)進(jìn)行線性插值來計算 collection view 的動畫參數(shù)抵拘。然而哎榴,新插入或者刪除的元素并沒有最初或最終狀態(tài)來進(jìn)行插值。要計算這樣的 cells 的動畫僵蛛,collection view 將通過 initialLayoutAttributesForAppearingItemAtIndexPath: 以及 finalLayoutAttributesForDisappearingItemAtIndexPath: 方法來詢問其布局對象尚蝌,以獲取最初的和最后的屬性。蘋果默認(rèn)的實(shí)現(xiàn)中墩瞳,對于特定的某個 indexPath驼壶,返回的是它的通常的位置,但 alpha 值為 0.0喉酌,這就產(chǎn)生了一個淡入或淡出動畫热凹。

簡而言之,就是蘋果自帶了插入刪除時Item的淡入淡出的動畫泪电,若你想自定義更炫的動畫般妙,就子類化UICollectionViewFlowLayout類,并重寫以下兩個方法:

// 初始狀態(tài)

  • (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;
    

}
// 終結(jié)狀態(tài)

  • (nullable UICollectionViewLayoutAttributes *)finalLayoutAttributesForDisappearingItemAtIndexPath:(NSIndexPath *)itemIndexPath
    {
    UICollectionViewLayoutAttributes *attr = [self layoutAttributesForItemAtIndexPath:itemIndexPath];
    attr.alpha = 0.0f;
    return attr;
    }```

insert&delete.gif

UICollectionView的轉(zhuǎn)場動畫
http://objccn.io/issue-12-5/

轉(zhuǎn)載http://www.reibang.com/p/c59a5c92f859 感謝作者

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末相速,一起剝皮案震驚了整個濱河市碟渺,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌突诬,老刑警劉巖苫拍,帶你破解...
    沈念sama閱讀 216,919評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異旺隙,居然都是意外死亡绒极,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,567評論 3 392
  • 文/潘曉璐 我一進(jìn)店門蔬捷,熙熙樓的掌柜王于貴愁眉苦臉地迎上來垄提,“玉大人榔袋,你說我怎么就攤上這事≌±” “怎么了凰兑?”我有些...
    開封第一講書人閱讀 163,316評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長审丘。 經(jīng)常有香客問我吏够,道長,這世上最難降的妖魔是什么备恤? 我笑而不...
    開封第一講書人閱讀 58,294評論 1 292
  • 正文 為了忘掉前任稿饰,我火速辦了婚禮,結(jié)果婚禮上露泊,老公的妹妹穿的比我還像新娘喉镰。我一直安慰自己,他們只是感情好惭笑,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,318評論 6 390
  • 文/花漫 我一把揭開白布侣姆。 她就那樣靜靜地躺著,像睡著了一般沉噩。 火紅的嫁衣襯著肌膚如雪捺宗。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,245評論 1 299
  • 那天川蒙,我揣著相機(jī)與錄音蚜厉,去河邊找鬼。 笑死畜眨,一個胖子當(dāng)著我的面吹牛昼牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播康聂,決...
    沈念sama閱讀 40,120評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼贰健,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了恬汁?” 一聲冷哼從身側(cè)響起伶椿,我...
    開封第一講書人閱讀 38,964評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎氓侧,沒想到半個月后脊另,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,376評論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡约巷,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,592評論 2 333
  • 正文 我和宋清朗相戀三年尝蠕,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片载庭。...
    茶點(diǎn)故事閱讀 39,764評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出囚聚,到底是詐尸還是另有隱情靖榕,我是刑警寧澤,帶...
    沈念sama閱讀 35,460評論 5 344
  • 正文 年R本政府宣布顽铸,位于F島的核電站茁计,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏谓松。R本人自食惡果不足惜星压,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,070評論 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望鬼譬。 院中可真熱鬧娜膘,春花似錦、人聲如沸优质。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,697評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽巩螃。三九已至演怎,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間避乏,已是汗流浹背爷耀。 一陣腳步聲響...
    開封第一講書人閱讀 32,846評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留拍皮,地道東北人歹叮。 一個月前我還...
    沈念sama閱讀 47,819評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像春缕,于是被迫代替她去往敵國和親盗胀。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,665評論 2 354

推薦閱讀更多精彩內(nèi)容