WWDC 2012 Session筆記——219 Advanced Collection Views and Building Custom Layouts
這是博主的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方法:
-(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放大。
自動對齊到網格
- (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) < ABS(offsetAdjustment)) {
offsetAdjustment = itemHorizontalCenter - horizontalCenter;
}
}
return CGPointMake(proposedContentOffset.x + offsetAdjustment, proposedContentOffset.y);
}
當前item放大
-(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) < 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的編寫流程,非常具有學習和借鑑的意義。
首先,佈局準備中定義了一些之後計算所需要用到的引數。
-(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子類的要求,過載了所需要的方法:
//整個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 < self.cellCount; i++) {
//這裡利用了-layoutAttributesForItemAtIndexPath:來獲取attributes
NSIndexPath* indexPath = [NSIndexPath indexPathForItem:i inSection:0];
[attributes addObject:[self layoutAttributesForItemAtIndexPath:indexPath]];
}
return attributes;
}
相關推薦
WWDC 2012 Session筆記——219 Advanced Collection Views and Building Custom Layouts
這是博主的WWDC2012筆記系列中的一篇,完整的筆記列表可以參看這裡。如果您是首次來到本站,也許您會有興趣通過RSS,或者通過頁面左側的郵件訂閱的方式訂閱本站。 在上一篇UICollectionView的入門介紹中,大概地對iOS6新加入的強大的UICollectio
WWDC 2012 Session筆記——202, 228, 232 AutoLayout(自動佈局)入門
Tagged iOS, objective-c, WWDC, Xcode, 開發 這是博主的WWDC2012筆記系列中的一篇,完整的筆記列表可以參看這裡。如果您是首次來到本站,也許您會有興趣通過RSS,或者通過頁面下方的郵件訂閱的方式訂閱本站。 AutoLayout
[ios-必看] WWDC 2013 Session筆記
iOS7的後臺多工特性 這是我的WWDC2013系列筆記中的一篇,完整的筆記列表請參看這篇總覽。本文僅作為個人記錄使用,也歡迎在許可協議範圍內轉載或使用,但是還煩請保留原文連結,謝謝您的理解合作。如果您覺得本站對您能有幫助,您可以使用RSS或郵件方式訂閱本站,這樣您將能在第一時間獲取本站資訊。 本文涉及到的
影象和圖形的最佳實踐(WWDC 2018 session 219)
該篇部落格記錄觀看WWDC2018中Session219《Image And Graphics Best Practices》的內容及一些理解。 該Session主要講述了關於有效使用圖形內容的一些技術和策略。主要分三個方面: 從UIImage和UIIma
Cookie&Session筆記
會話技術 會話:一次會話中包含多次請求和響應 一次會話:瀏覽器第一次給伺服器資源傳送請求,會話建立,直到有一方斷開為止 功能:在一次會話的範圍內的多次請求間共享資料 方式: 客戶端會話技術:Cookie 伺服器端會話技術:Session Cookie 概念:客戶端會話技術,將資料
高效的使用集合(WWDC 2018 session 229)
該篇部落格記錄了觀看WWDC Session229《Using collections effectively》的內容以及一些理解。 該Session講解了在Swift中高效使用集合的一些注意點。 假如沒有集合 假如沒有Arrays 假如沒有Arra
使用日誌記錄來衡量效能(WWDC 2018 session 405)
引言 效能是實現卓越的使用者體驗的關鍵之一。當應用或者遊戲表現的執行迅速,反應靈敏時,使用者會更喜歡。但是軟體是很複雜的,當你的應用檢視做某事時,例如只是點了一個按鈕,但程式也有可能做了很多的事情,這就意味著你可以在一些看似不太可能的地方找到一些優化點
java筆記2——集合Collection
目錄 三、集合 一、為什麼會有集合?陣列不能滿足使用嗎? 首先Java是面向物件的語言,需要通過物件體現。為了方便對多個物件進行操作,我們需要儲存多個物件的容器。 目前學過的容器有StringBuffer和陣列。但是Str
斯坦福大學公開課 iOS應用開發教程學習筆記(第四課) Views 檢視
第四課名稱: Views 檢視 課程開始老師懷念了一會老喬。接著介紹這次的課程分為兩部分,一部分是Calculator的Demo,一部分是Views. 課程開始到第四課,其實斯坦福的課程裡是有作業的,人家已經做完了第一個作業了,就是完善計算器這個程式,完成一個比較複雜
[學習筆記] CS131 Computer Vision: Foundations and Applications:Lecture 1 課程介紹
rac git mea under https bridge cau found cts 課程大綱:http://vision.stanford.edu/teaching/cs131_fall1718/syllabus.html 課程定位: 課程交叉:
[學習筆記] CS131 Computer Vision: Foundations and Applications:Lecture 2 顏色和數學基礎
rgb 數學 histogram val 顏色 models hist nor 學習 大綱 what is color? The result of interaction between physical light in the environment
[學習筆記] CS131 Computer Vision: Foundations and Applications:Lecture 9 深度學習2
math found deep als fin regress ural nsf -m 深度學習 So far this week Edge detection RANSAC SIFT K-Means Linear classifier Mean-shift PCA/Ei
c4d 幫助 prime r16 --views and viewports
圖標 很多 nbsp 幫助 pri 如果 bsp 設備 菜單 c4d 幫助 prime r16 --views and viewports 視窗和接口 你能夠像你喜歡的那樣打開很多的視圖面板,每個視圖面板都有它自己的顯示設定 一個顯示免納能夠顯示4個視圖接口(一個
[Python學習筆記-002] lambda, map, filter and reduce
參考 例如 target get 。。 python 參考資料 span else 1. lambda lambda, 即匿名函數,可以理解為跟C語言的宏類似。例如: >>> max = lambda x, y: x if x > y else y
《機器學習》筆記--4 整合學習boosting and bagging
Boosting 特點:個體學習器之間存在強依賴關係、必須序列生成的方法。關注偏差的降低。 方法: 先從初始訓練集選練出一個弱學習器,再根據弱學習器的表現進行樣本分佈的調整,提高那些被錯誤學習的樣本的權值,降低那些被正確學習的樣本的權值,然後繼續訓練下一個弱學習器。最後將一
CSS學習筆記-CSS的優先順序問題 AND 2018-11-21(21:58)
一、優先順序問題 內聯樣式表>內部樣式表>外部樣式表:就近原則 例如: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>CS
【讀書筆記】《Computer Organization and Design: The Hardware/Software Interface》(1)
筆記前言: 《Computer Organization and Design: The Hardware/Software Interface》,中文譯名,《計算機組成與設計:硬體/軟體介面》,是計算機組成原理的經典入門教材之一。節奏緊湊又不緊張,內容充實又不冗長,語言表述樸實易懂又不故作高深,是一本非常
《Beginning C++17》-學習筆記-Chapter 10-Program Files and Preprocessing Directives
#include "..\Power.h" /*including the file called Power.h located in the folder that includes the foler that includes this file.*/ Each source file
[分散式系統學習]閱讀筆記 Distributed systems for fun and profit 之一 基本概念
因為工作的原因,最近打算看一些分散式學習的資料。其中這個http://book.mixu.net/distsys/就是一篇非常適合分散式入門的介紹。 這個短小的材料有下面5個小的章節,圖文並茂,也沒有太難的概念,非常推薦。 基礎知識。主要是一些基本概念,例如可擴充套件性(scalability),可用
[分散式系統學習]閱讀筆記 Distributed systems for fun and profit 之四 Replication 拷貝
閱讀http://book.mixu.net/distsys/replication.html的筆記,是本系列的第四章 拷貝其實是一組通訊問題,為一些子問題,例如選舉,失靈檢測,一致性和原子廣播提供了上下文。 同步拷貝 可以看到三個不同階段,首先client傳送請求。然後同步拷貝,同步意味著這