IOS學習 UICollectionViewLayout基本使用

 

UICollectionViewLayout


目錄(?)[+

這是博主的WWDC2012筆記系列中的一篇,完整的筆記列表可以參看這裏。如果您是首次來到本站,也許您會有興趣通過RSS,或者通過頁面左側的郵件訂閱的方式訂閱本站。

在上一篇UICollectionView的入門介紹中,大概地對iOS6新加入的強大的UICollectionView進行了一些說明。在這篇博文中,將結合WWDC2012 Session219:Advanced Collection View的內容,對Collection View進行一個深入的使用探討,並給出一個自定義的Demo。

UICollectionView的結構回顧

首先回顧一下Collection View的構成,我們能看到的有三個部分:

  • Cells
  • Supplementary Views 追加視圖 (類似Header或者Footer)
  • Decoration Views 裝飾視圖 (用作背景展示)

而在表面下,由兩個方面對UICollectionView進行支持。其中之一和tableView一樣,即提供數據的UICollectionViewDataSource以及處理用戶交互的UICollectionViewDelegate。另一方面,對於cell的樣式和組織方式,由於collectionView比tableView要複雜得多,因此沒有按照類似於tableView的style的方式來定義,而是專門使用了一個類來對collectionView的佈局和行爲進行描述,這就是UICollectionViewLayout。

這次的筆記將把重點放在UICollectionViewLayout上,因爲這不僅是collectionView和tableView的最重要求的區別,也是整個UICollectionView的精髓所在。

如果對UICollectionView的基本構成要素和使用方法還不清楚的話,可以移步到我之前的一篇筆記:Session筆記——205 Introducing Collection Views中進行一些瞭解。


UICollectionViewLayoutAttributes

UICollectionViewLayoutAttributes是一個非常重要的類,先來看看property列表:

  • @property (nonatomic) CGRect frame
  • @property (nonatomic) CGPoint center
  • @property (nonatomic) CGSize size
  • @property (nonatomic) CATransform3D transform3D
  • @property (nonatomic) CGFloat alpha
  • @property (nonatomic) NSInteger zIndex
  • @property (nonatomic, getter=isHidden) BOOL hidden

可以看到,UICollectionViewLayoutAttributes的實例中包含了諸如邊框,中心點,大小,形狀,透明度,層次關係和是否隱藏等信息。和DataSource的行爲十分類似,當UICollectionView在獲取佈局時將針對每一個indexPath的部件(包括cell,追加視圖和裝飾視圖),向其上的UICollectionViewLayout實例詢問該部件的佈局信息(在這個層面上說的話,實現一個UICollectionViewLayout的時候,其實很像是zap一個delegate,之後的例子中會很明顯地看出),這個佈局信息,就以UICollectionViewLayoutAttributes的實例的方式給出。


自定義的UICollectionViewLayout

UICollectionViewLayout的功能爲向UICollectionView提供佈局信息,不僅包括cell的佈局信息,也包括追加視圖和裝飾視圖的佈局信息。實現一個自定義layout的常規做法是繼承UICollectionViewLayout類,然後重載下列方法:

  • -(CGSize)collectionViewContentSize

    • 返回collectionView的內容的尺寸
  • -(NSArray *)layoutAttributesForElementsInRect:(CGRect)rect

    • 返回rect中的所有的元素的佈局屬性
    • 返回的是包含UICollectionViewLayoutAttributes的NSArray
    • UICollectionViewLayoutAttributes可以是cell,追加視圖或裝飾視圖的信息,通過不同的UICollectionViewLayoutAttributes初始化方法可以得到不同類型的UICollectionViewLayoutAttributes:

      • layoutAttributesForCellWithIndexPath:
      • layoutAttributesForSupplementaryViewOfKind:withIndexPath:
      • layoutAttributesForDecorationViewOfKind:withIndexPath:
  • -(UICollectionViewLayoutAttributes )layoutAttributesForItemAtIndexPath:(NSIndexPath )indexPath

    • 返回對應於indexPath的位置的cell的佈局屬性
  • -(UICollectionViewLayoutAttributes )layoutAttributesForSupplementaryViewOfKind:(NSString )kind atIndexPath:(NSIndexPath *)indexPath

    • 返回對應於indexPath的位置的追加視圖的佈局屬性,如果沒有追加視圖可不重載
  • -(UICollectionViewLayoutAttributes * )layoutAttributesForDecorationViewOfKind:(NSString)decorationViewKind atIndexPath:(NSIndexPath )indexPath

    • 返回對應於indexPath的位置的裝飾視圖的佈局屬性,如果沒有裝飾視圖可不重載
  • -(BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds

    • 當邊界發生改變時,是否應該刷新佈局。如果YES則在邊界變化(一般是scroll到其他地方)時,將重新計算需要的佈局信息。

另外需要了解的是,在初始化一個UICollectionViewLayout實例後,會有一系列準備方法被自動調用,以保證layout實例的正確。

首先,-(void)prepareLayout將被調用,默認下該方法什麼沒做,但是在自己的子類實現中,一般在該方法中設定一些必要的layout的結構和初始需要的參數等。

之後,-(CGSize) collectionViewContentSize將被調用,以確定collection應該佔據的尺寸。注意這裏的尺寸不是指可視部分的尺寸,而應該是所有內容所佔的尺寸。collectionView的本質是一個scrollView,因此需要這個尺寸來配置滾動行爲。

接下來-(NSArray *)layoutAttributesForElementsInRect:(CGRect)rect被調用,這個沒什麼值得多說的。初始的layout的外觀將由該方法返回的UICollectionViewLayoutAttributes來決定。

另外,在需要更新layout時,需要給當前layout發送 -invalidateLayout,該消息會立即返回,並且預約在下一個loop的時候刷新當前layout,這一點和UIView的setNeedsLayout方法十分類似。在-invalidateLayout後的下一個collectionView的刷新loop中,又會從prepareLayout開始,依次再調用-collectionViewContentSize和-layoutAttributesForElementsInRect來生成更新後的佈局。


Demo

說了那麼多,其實還是Demo最能解決問題。Apple官方給了一個flow layout和一個circle layout的例子,都很經典,需要的同學可以從這裏下載

LineLayout——對於個別UICollectionViewLayoutAttributes的調整

先看LineLayout,它繼承了UICollectionViewFlowLayout這個Apple提供的基本的佈局。它主要實現了單行佈局,自動對齊到網格以及當前網格cell放大三個特性。如圖:

先看LineLayout的init方法:

<span class="line-number" style="margin: 0px; padding: 0px;">1</span>
<span class="line-number" style="margin: 0px; padding: 0px;">2</span>
<span class="line-number" style="margin: 0px; padding: 0px;">3</span>
<span class="line-number" style="margin: 0px; padding: 0px;">4</span>
<span class="line-number" style="margin: 0px; padding: 0px;">5</span>
<span class="line-number" style="margin: 0px; padding: 0px;">6</span>
<span class="line-number" style="margin: 0px; padding: 0px;">7</span>
<span class="line-number" style="margin: 0px; padding: 0px;">8</span>
<span class="line-number" style="margin: 0px; padding: 0px;">9</span>
<span class="line-number" style="margin: 0px; padding: 0px;">10</span>
<span class="line-number" style="margin: 0px; padding: 0px;">11</span>
-(id)init
{
    self = [super init];
    if (self) {
        self.itemSize = CGSizeMake(ITEM_SIZE, ITEM_SIZE);
        self.scrollDirection = UICollectionViewScrollDirectionHorizontal;
        self.sectionInset = UIEdgeInsetsMake(200, 0.0, 200, 0.0);
        self.minimumLineSpacing = 50.0;
    }
    return self;
}

self.sectionInset = UIEdgeInsetsMake(200, 0.0, 200, 0.0); 確定了縮進,此處爲上方和下方各縮進200個point。由於cell的size已經定義了爲200x200,因此屏幕上在縮進後就只有一排item的空間了。

self.minimumLineSpacing = 50.0; 這個定義了每個item在水平方向上的最小間距。

UICollectionViewFlowLayout是Apple爲我們準備的開袋即食的現成佈局,因此之前提到的幾個必須重載的方法中需要我們操心的很少,即使完全不重載它們,現在也可以得到一個不錯的線狀一行的gridview了。而我們的LineLayout通過重載父類方法後,可以實現一些新特性,比如這裏的動對齊到網格以及當前網格cell放大。

自動對齊到網格

<span class="line-number" style="margin: 0px; padding: 0px;">1</span>
<span class="line-number" style="margin: 0px; padding: 0px;">2</span>
<span class="line-number" style="margin: 0px; padding: 0px;">3</span>
<span class="line-number" style="margin: 0px; padding: 0px;">4</span>
<span class="line-number" style="margin: 0px; padding: 0px;">5</span>
<span class="line-number" style="margin: 0px; padding: 0px;">6</span>
<span class="line-number" style="margin: 0px; padding: 0px;">7</span>
<span class="line-number" style="margin: 0px; padding: 0px;">8</span>
<span class="line-number" style="margin: 0px; padding: 0px;">9</span>
<span class="line-number" style="margin: 0px; padding: 0px;">10</span>
<span class="line-number" style="margin: 0px; padding: 0px;">11</span>
<span class="line-number" style="margin: 0px; padding: 0px;">12</span>
<span class="line-number" style="margin: 0px; padding: 0px;">13</span>
<span class="line-number" style="margin: 0px; padding: 0px;">14</span>
<span class="line-number" style="margin: 0px; padding: 0px;">15</span>
<span class="line-number" style="margin: 0px; padding: 0px;">16</span>
<span class="line-number" style="margin: 0px; padding: 0px;">17</span>
- (CGPoint)targetContentOffsetForProposedContentOffset: (CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity
{
    //proposedContentOffset是沒有對齊到網格時本來應該停下的位置
    CGFloat offsetAdjustment = MAXFLOAT;
    CGFloat horizontalCenter = proposedContentOffset.x + (CGRectGetWidth(self.collectionView.bounds) / 2.0);
    CGRect targetRect = CGRectMake(proposedContentOffset.x, 0.0, self.collectionView.bounds.size.width, self.collectionView.bounds.size.height);
    NSArray* array = [super layoutAttributesForElementsInRect:targetRect];

    //對當前屏幕中的UICollectionViewLayoutAttributes逐個與屏幕中心進行比較,找出最接近中心的一個
    for (UICollectionViewLayoutAttributes* layoutAttributes in array) {
        CGFloat itemHorizontalCenter = layoutAttributes.center.x;
        if (ABS(itemHorizontalCenter - horizontalCenter) &lt; ABS(offsetAdjustment)) {
            offsetAdjustment = itemHorizontalCenter - horizontalCenter;
        }
    }
    return CGPointMake(proposedContentOffset.x + offsetAdjustment, proposedContentOffset.y);
}

當前item放大

<span class="line-number" style="margin: 0px; padding: 0px;">1</span>
<span class="line-number" style="margin: 0px; padding: 0px;">2</span>
<span class="line-number" style="margin: 0px; padding: 0px;">3</span>
<span class="line-number" style="margin: 0px; padding: 0px;">4</span>
<span class="line-number" style="margin: 0px; padding: 0px;">5</span>
<span class="line-number" style="margin: 0px; padding: 0px;">6</span>
<span class="line-number" style="margin: 0px; padding: 0px;">7</span>
<span class="line-number" style="margin: 0px; padding: 0px;">8</span>
<span class="line-number" style="margin: 0px; padding: 0px;">9</span>
<span class="line-number" style="margin: 0px; padding: 0px;">10</span>
<span class="line-number" style="margin: 0px; padding: 0px;">11</span>
<span class="line-number" style="margin: 0px; padding: 0px;">12</span>
<span class="line-number" style="margin: 0px; padding: 0px;">13</span>
<span class="line-number" style="margin: 0px; padding: 0px;">14</span>
<span class="line-number" style="margin: 0px; padding: 0px;">15</span>
<span class="line-number" style="margin: 0px; padding: 0px;">16</span>
<span class="line-number" style="margin: 0px; padding: 0px;">17</span>
<span class="line-number" style="margin: 0px; padding: 0px;">18</span>
<span class="line-number" style="margin: 0px; padding: 0px;">19</span>
<span class="line-number" style="margin: 0px; padding: 0px;">20</span>
-(NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
{
    NSArray *array = [super layoutAttributesForElementsInRect:rect];
    CGRect visibleRect;
    visibleRect.origin = self.collectionView.contentOffset;
    visibleRect.size = self.collectionView.bounds.size;

    for (UICollectionViewLayoutAttributes* attributes in array) {
        if (CGRectIntersectsRect(attributes.frame, rect)) {
            CGFloat distance = CGRectGetMidX(visibleRect) - attributes.center.x;
            CGFloat normalizedDistance = distance / ACTIVE_DISTANCE;
            if (ABS(distance) &lt; ACTIVE_DISTANCE) {
                CGFloat zoom = 1 + ZOOM_FACTOR*(1 - ABS(normalizedDistance));
                attributes.transform3D = CATransform3DMakeScale(zoom, zoom, 1.0);
                attributes.zIndex = 1;
            }
        }
    }
    return array;
}

對於個別UICollectionViewLayoutAttributes進行調整,以達到滿足設計需求是UICollectionView使用中的一種思路。在根據位置提供不同layout屬性的時候,需要記得讓-shouldInvalidateLayoutForBoundsChange:返回YES,這樣當邊界改變的時候,-invalidateLayout會自動被髮送,才能讓layout得到刷新。

CircleLayout——完全自定義的Layout,添加刪除item,以及手勢識別

CircleLayout的例子稍微複雜一些,cell分佈在圓周上,點擊cell的話會將其從collectionView中移出,點擊空白處會加入一個cell,加入和移出都有動畫效果。

這放在以前的話估計夠寫一陣子了,而得益於UICollectionView,基本只需要100來行代碼就可以搞定這一切,非常cheap。通過CircleLayout的實現,可以完整地看到自定義的layout的編寫流程,非常具有學習和借鑑的意義。

CircleLayoutCircleLayout

首先,佈局準備中定義了一些之後計算所需要用到的參數。

<span class="line-number" style="margin: 0px; padding: 0px;">1</span>
<span class="line-number" style="margin: 0px; padding: 0px;">2</span>
<span class="line-number" style="margin: 0px; padding: 0px;">3</span>
<span class="line-number" style="margin: 0px; padding: 0px;">4</span>
<span class="line-number" style="margin: 0px; padding: 0px;">5</span>
<span class="line-number" style="margin: 0px; padding: 0px;">6</span>
<span class="line-number" style="margin: 0px; padding: 0px;">7</span>
<span class="line-number" style="margin: 0px; padding: 0px;">8</span>
<span class="line-number" style="margin: 0px; padding: 0px;">9</span>
-(void)prepareLayout
{   //和init相似,必須call super的prepareLayout以保證初始化正確
    [super prepareLayout];

    CGSize size = self.collectionView.frame.size;
    _cellCount = [[self collectionView] numberOfItemsInSection:0];
    _center = CGPointMake(size.width / 2.0, size.height / 2.0);
    _radius = MIN(size.width, size.height) / 2.5;
}

其實對於一個size不變的collectionView來說,除了_cellCount之外的中心和半徑的定義也可以扔到init裏去做,但是顯然在prepareLayout裏做的話具有更大的靈活性。因爲每次重新給出layout時都會調用prepareLayout,這樣在以後如果有collectionView大小變化的需求時也可以自動適應變化。

然後,按照UICollectionViewLayout子類的要求,重載了所需要的方法:

<span class="line-number" style="margin: 0px; padding: 0px;">1</span>
<span class="line-number" style="margin: 0px; padding: 0px;">2</span>
<span class="line-number" style="margin: 0px; padding: 0px;">3</span>
<span class="line-number" style="margin: 0px; padding: 0px;">4</span>
<span class="line-number" style="margin: 0px; padding: 0px;">5</span>
<span class="line-number" style="margin: 0px; padding: 0px;">6</span>
<span class="line-number" style="margin: 0px; padding: 0px;">7</span>
<span class="line-number" style="margin: 0px; padding: 0px;">8</span>
<span class="line-number" style="margin: 0px; padding: 0px;">9</span>
<span class="line-number" style="margin: 0px; padding: 0px;">10</span>
<span class="line-number" style="margin: 0px; padding: 0px;">11</span>
<span class="line-number" style="margin: 0px; padding: 0px;">12</span>
<span class="line-number" style="margin: 0px; padding: 0px;">13</span>
<span class="line-number" style="margin: 0px; padding: 0px;">14</span>
<span class="line-number" style="margin: 0px; padding: 0px;">15</span>
<span class="line-number" style="margin: 0px; padding: 0px;">16</span>
<span class="line-number" style="margin: 0px; padding: 0px;">17</span>
<span class="line-number" style="margin: 0px; padding: 0px;">18</span>
<span class="line-number" style="margin: 0px; padding: 0px;">19</span>
<span class="line-number" style="margin: 0px; padding: 0px;">20</span>
<span class="line-number" style="margin: 0px; padding: 0px;">21</span>
<span class="line-number" style="margin: 0px; padding: 0px;">22</span>
<span class="line-number" style="margin: 0px; padding: 0px;">23</span>
<span class="line-number" style="margin: 0px; padding: 0px;">24</span>
<span class="line-number" style="margin: 0px; padding: 0px;">25</span>
<span class="line-number" style="margin: 0px; padding: 0px;">26</span>
<span class="line-number" style="margin: 0px; padding: 0px;">27</span>
//整個collectionView的內容大小就是collectionView的大小(沒有滾動)
-(CGSize)collectionViewContentSize
{
    return [self collectionView].frame.size;
}

//通過所在的indexPath確定位置。
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)path
{
    UICollectionViewLayoutAttributes* attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:path]; //生成空白的attributes對象,其中只記錄了類型是cell以及對應的位置是indexPath
    //配置attributes到圓周上
    attributes.size = CGSizeMake(ITEM_SIZE, ITEM_SIZE);
    attributes.center = CGPointMake(_center.x + _radius * cosf(2 * path.item * M_PI / _cellCount), _center.y + _radius * sinf(2 * path.item * M_PI / _cellCount));
    return attributes;
}

//用來在一開始給出一套UICollectionViewLayoutAttributes
-(NSArray*)layoutAttributesForElementsInRect:(CGRect)rect
{
    NSMutableArray* attributes = [NSMutableArray array];
    for (NSInteger i=0 ; i &lt; self.cellCount; i++) {
        //這裏利用了-layoutAttributesForItemAtIndexPath:來獲取attributes
        NSIndexPath* indexPath = [NSIndexPath indexPathForItem:i inSection:0];
        [attributes addObject:[self layoutAttributesForItemAtIndexPath:indexPath]];
    }
    return attributes;
}

現在已經得到了一個circle layout。爲了實現cell的添加和刪除,需要爲collectionView加上手勢識別,這個很簡單,在ViewController中:

<span class="line-number" style="margin: 0px; padding: 0px;">1</span>
<span class="line-number" style="margin: 0px; padding: 0px;">2</span>
UITapGestureRecognizer* tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTapGesture:)];
[self.collectionView addGestureRecognizer:tapRecognizer];

對應的處理方法handleTapGesture:爲

<span class="line-number" style="margin: 0px; padding: 0px;">1</span>
<span class="line-number" style="margin: 0px; padding: 0px;">2</span>
<span class="line-number" style="margin: 0px; padding: 0px;">3</span>
<span class="line-number" style="margin: 0px; padding: 0px;">4</span>
<span class="line-number" style="margin: 0px; padding: 0px;">5</span>
<span class="line-number" style="margin: 0px; padding: 0px;">6</span>
<span class="line-number" style="margin: 0px; padding: 0px;">7</span>
<span class="line-number" style="margin: 0px; padding: 0px;">8</span>
<span class="line-number" style="margin: 0px; padding: 0px;">9</span>
<span class="line-number" style="margin: 0px; padding: 0px;">10</span>
<span class="line-number" style="margin: 0px; padding: 0px;">11</span>
<span class="line-number" style="margin: 0px; padding: 0px;">12</span>
<span class="line-number" style="margin: 0px; padding: 0px;">13</span>
<span class="line-number" style="margin: 0px; padding: 0px;">14</span>
<span class="line-number" style="margin: 0px; padding: 0px;">15</span>
<span class="line-number" style="margin: 0px; padding: 0px;">16</span>
<span class="line-number" style="margin: 0px; padding: 0px;">17</span>
- (void)handleTapGesture:(UITapGestureRecognizer *)sender {
    if (sender.state == UIGestureRecognizerStateEnded) {
        CGPoint initialPinchPoint = [sender locationInView:self.collectionView];
        NSIndexPath* tappedCellPath = [self.collectionView indexPathForItemAtPoint:initialPinchPoint]; //獲取點擊處的cell的indexPath
        if (tappedCellPath!=nil) { //點擊處沒有cell
            self.cellCount = self.cellCount - 1;
            [self.collectionView performBatchUpdates:^{
                [self.collectionView deleteItemsAtIndexPaths:[NSArray arrayWithObject:tappedCellPath]];
            } completion:nil];
        } else {
            self.cellCount = self.cellCount + 1;
            [self.collectionView performBatchUpdates:^{
                [self.collectionView insertItemsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForItem:0 inSection:0]]];
            } completion:nil];
        }
    }
}

performBatchUpdates:completion: 再次展示了block的強大的一面..這個方法可以用來對collectionView中的元素進行批量的插入,刪除,移動等操作,同時將觸發collectionView所對應的layout的對應的動畫。相應的動畫由layout中的下列四個方法來定義:

  • initialLayoutAttributesForAppearingItemAtIndexPath:
  • initialLayoutAttributesForAppearingDecorationElementOfKind:atIndexPath:
  • finalLayoutAttributesForDisappearingItemAtIndexPath:
  • finalLayoutAttributesForDisappearingDecorationElementOfKind:atIndexPath:

更正:正式版中API發生了變化(而且不止一次變化 initialLayoutAttributesForInsertedItemAtIndexPath:在正式版中已經被廢除。現在在insert或者delete之前,prepareForCollectionViewUpdates:會被調用,可以使用這個方法來完成添加/刪除的佈局。關於更多這方面的內容以及新的示例demo,可以參看這篇博文(需要翻牆)。新的示例demo在Github上也有,鏈接

在CircleLayout中,實現了cell的動畫。

<span class="line-number" style="margin: 0px; padding: 0px;">1</span>
<span class="line-number" style="margin: 0px; padding: 0px;">2</span>
<span class="line-number" style="margin: 0px; padding: 0px;">3</span>
<span class="line-number" style="margin: 0px; padding: 0px;">4</span>
<span class="line-number" style="margin: 0px; padding: 0px;">5</span>
<span class="line-number" style="margin: 0px; padding: 0px;">6</span>
<span class="line-number" style="margin: 0px; padding: 0px;">7</span>
<span class="line-number" style="margin: 0px; padding: 0px;">8</span>
<span class="line-number" style="margin: 0px; padding: 0px;">9</span>
<span class="line-number" style="margin: 0px; padding: 0px;">10</span>
<span class="line-number" style="margin: 0px; padding: 0px;">11</span>
<span class="line-number" style="margin: 0px; padding: 0px;">12</span>
<span class="line-number" style="margin: 0px; padding: 0px;">13</span>
<span class="line-number" style="margin: 0px; padding: 0px;">14</span>
<span class="line-number" style="margin: 0px; padding: 0px;">15</span>
<span class="line-number" style="margin: 0px; padding: 0px;">16</span>
<span class="line-number" style="margin: 0px; padding: 0px;">17</span>
<span class="line-number" style="margin: 0px; padding: 0px;">18</span>
//插入前,cell在圓心位置,全透明
- (UICollectionViewLayoutAttributes *)initialLayoutAttributesForInsertedItemAtIndexPath:(NSIndexPath *)itemIndexPath
{
    UICollectionViewLayoutAttributes* attributes = [self layoutAttributesForItemAtIndexPath:itemIndexPath];
    attributes.alpha = 0.0;
    attributes.center = CGPointMake(_center.x, _center.y);
    return attributes;
}

//刪除時,cell在圓心位置,全透明,且只有原來的1/10大
- (UICollectionViewLayoutAttributes *)finalLayoutAttributesForDeletedItemAtIndexPath:(NSIndexPath *)itemIndexPath
{
    UICollectionViewLayoutAttributes* attributes = [self layoutAttributesForItemAtIndexPath:itemIndexPath];
    attributes.alpha = 0.0;
    attributes.center = CGPointMake(_center.x, _center.y);
    attributes.transform3D = CATransform3DMakeScale(0.1, 0.1, 1.0);
    return attributes;
}

在插入或刪除時,將分別以插入前和刪除後的attributes和普通狀態下的attributes爲基準,進行UIView的動畫過渡。而這一切並沒有很多代碼要寫,幾乎是free的,感謝蘋果…


佈局之間的切換

有時候可能需要不同的佈局,Apple也提供了方便的佈局間切換的方法。直接更改collectionView的collectionViewLayout屬性可以立即切換佈局。而如果通過setCollectionViewLayout:animated:,則可以在切換佈局的同時,使用動畫來過渡。對於每一個cell,都將有對應的UIView動畫進行對應,又是一個接近free的特性。

對於我自己來說,UICollectionView可能是我轉向iOS 6 SDK的最具有吸引力的特性之一,因爲UIKit團隊的努力和CoreAnimation的成熟,使得創建一個漂亮優雅的UI變的越來越簡單了。可以斷言說UICollectionView在今後的iOS開發中,一定會成爲和UITableView一樣的強大和最常用的類之一。在iOS 6還未正式上市前,先對其特性進行一些學習,以期儘快能使用新特性來簡化開發流程,可以說是非常值得的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章