創(chuàng)建自定義布局
在開始創(chuàng)建自定義布局之前,考慮清楚是否有這個(gè)必要。UICollectionViewFlowLayout
類提供了大量已經(jīng)對(duì)效率進(jìn)行優(yōu)化了的行為,并且可以通過多種方式進(jìn)行調(diào)整,來實(shí)現(xiàn)許多不同類型的標(biāo)準(zhǔn)布局。唯一需要考慮實(shí)現(xiàn)自定義布局是在以下情況下:
- 你想要的布局看前來不像網(wǎng)格或基于線性中斷布局(布局中
items
被放置到一行,直到這一行布滿了,然后繼續(xù)布到下一行,直到所有的items
被放置),或者需要不止在一個(gè)方向上滾動(dòng)。 - 你想要頻繁地改變所有單元格的位置,而修改已經(jīng)存在的流式布局比創(chuàng)建自定義布局要做更多的工作。
好消息是,從API的角度來看,實(shí)現(xiàn)自定義布局并不難。最困難的部分是執(zhí)行必要的計(jì)算來確定布局中items
的位置。當(dāng)你知道了這些items
的位置,給集合視圖提供那些信息是很簡(jiǎn)單的。
子類化UICollectionViewLayout
對(duì)于自定義布局,你想要子類化UICollectionViewLayout
,這為你的設(shè)計(jì)提供了一個(gè)新的起點(diǎn)。只有少數(shù)方法為你的布局對(duì)象提供了核心的行為,并且在你的實(shí)現(xiàn)中是必須的。其余的方法可以根據(jù)需要來重寫以調(diào)整布局行為。核心方法處理以下關(guān)鍵任務(wù):
- 指定可滾動(dòng)內(nèi)容區(qū)域的大小。
- 為構(gòu)成布局的單元格和視圖提供屬性對(duì)象,以便集合視圖可以定位每個(gè)單元格和視圖。
雖讓你可以創(chuàng)建一個(gè)僅實(shí)現(xiàn)核心方法的功能性布局對(duì)象,但如果你也實(shí)現(xiàn)了幾種可選方法,布局可能會(huì)更有吸引力。
布局對(duì)象使用它的數(shù)據(jù)源提供的信息來創(chuàng)建集合視圖的布局。你的布局通過調(diào)用collectionView
屬性的方法來與數(shù)據(jù)源進(jìn)行通信,該方法可以在所有布局的方法中訪問。記住你的集合視圖在布局過程中知道和不知道的內(nèi)容。由于布局過程正在進(jìn)行,集合視圖無法跟蹤視圖的布局或位置。因此,即使布局對(duì)象不會(huì)限制你調(diào)用集合視圖的任何方法,也不要依賴于集合視圖來計(jì)算布局所需的數(shù)據(jù)以外的其他內(nèi)容。
理解核心布局過程
集合視圖直接與你的自定義布局對(duì)象一起工作來管理整個(gè)布局過程。當(dāng)集合視圖確定它需要布局信息時(shí),它會(huì)讓你的布局對(duì)象來提供。例如,集合視圖會(huì)在首次顯示或調(diào)整大小時(shí)詢問布局信息。你也可以通過調(diào)用布局對(duì)象的invalidateLayout
方法告訴集合視圖來顯式地更新它的布局。該方法扔掉已經(jīng)存在的布局信息,并強(qiáng)制布局對(duì)象生成新的布局信息。
注意:不要將布局對(duì)象的
invalidateLayout
方法和集合視圖的reloadData
方法混淆。調(diào)用invalidateLayout
方法不一定會(huì)導(dǎo)致集合視圖拋出其現(xiàn)有的單元格和子視圖。而是,它強(qiáng)制布局對(duì)象來重新計(jì)算其當(dāng)移動(dòng)和添加或刪除items
時(shí)所需的所有布局屬性。如果數(shù)據(jù)源中的數(shù)據(jù)已更改,則reloadData
方法是合適的。無論你如何啟動(dòng)布局更新,實(shí)際的布局過程是一樣的。
在布局過程中,集合視圖會(huì)調(diào)用你的布局對(duì)象的特定方法。這些方法是你計(jì)算items
位置的機(jī)會(huì),并為集合視圖提供所需的主要信息。其他方法也可能被調(diào)用,但是在布局過程中總是按照以下順序調(diào)用這些方法:
- 使用
prepareLayout
方法來執(zhí)行提供布局信息所需的前期計(jì)算。 - 使用
collectionViewContentSize
方法來根據(jù)初始計(jì)算返回整個(gè)內(nèi)容區(qū)域的總體大小。 - 使用
layoutAttributesForElementsInRect:
方法來返回指定矩形中的單元格和視圖的屬性。
圖5-1 說明如何使用上述方法生成布局信息
prepareLayout
方法是你執(zhí)行任何計(jì)算來確定在布局中單元格和視圖的位置的機(jī)會(huì)。至少,你應(yīng)該在這個(gè)方法中計(jì)算足夠的信息,以便返回內(nèi)容區(qū)域的整體大小,在步驟2中以返回給集合視圖。
集合視圖使用內(nèi)容的大小來適當(dāng)?shù)嘏渲盟臐L動(dòng)視圖。例如,如果計(jì)算的內(nèi)容在縱向和橫向上超過當(dāng)前設(shè)備屏幕的邊界,則滾動(dòng)視圖將進(jìn)行調(diào)整,以便同時(shí)在兩個(gè)方向上滾動(dòng)。不像UICollectionViewFlowLayout
, 默認(rèn)不調(diào)整布局的內(nèi)容,只在一個(gè)方向上滾動(dòng)。
基于當(dāng)前滾動(dòng)位置,然后集合視圖調(diào)用你的layoutAttributesForElementsInRect:
方法來詢問在特定矩形內(nèi)的單元格和視圖的屬性,這可能或不可能與可見矩形相同。返回那些信息之后,核心布局過程就有效地完成了。
在布局完成之后,你的單元格和視圖的屬性會(huì)保持不變,直到你或集合視圖無效化布局。調(diào)用布局對(duì)象的nvalidateLayout
方法會(huì)導(dǎo)致布局過程重新開始,才從prepareLayout
方法的新調(diào)用開始。集合視圖在滾動(dòng)期間能夠自動(dòng)地?zé)o效你的布局。如果用戶滾動(dòng)其內(nèi)容,集合視圖會(huì)調(diào)用布局對(duì)象的shouldInvalidateLayoutForBoundsChange:
方法,如果該方法返回YES
,則會(huì)使布局無效。
注意:記住調(diào)用
invalidateLayout
方法不會(huì)立即開始布局更新過程是有用的。該方法僅將布局標(biāo)記為與數(shù)據(jù)不一致并需要更新。在下一個(gè)視圖更新周期中,集合視圖會(huì)檢查其布局是否不一致,如果是則更新它。事實(shí)上,你可以快速連續(xù)地調(diào)用invalidateLayout
方法,而不會(huì)每次觸發(fā)立即布局更新。
創(chuàng)建布局屬性
你的布局負(fù)責(zé)的屬性對(duì)象是UICollectionViewLayoutAttributes
類的實(shí)例。在你的應(yīng)用程序中這些實(shí)例可以被多種不同的方法來創(chuàng)建。當(dāng)你的應(yīng)用程序不處理數(shù)千個(gè)items
時(shí),在準(zhǔn)備布局時(shí)才創(chuàng)建這些實(shí)例是有意義的,因?yàn)椴季中畔⒖梢跃彺婧鸵茫皇羌磿r(shí)計(jì)算。如果計(jì)算所有屬性的成本高于應(yīng)用程序緩存的好處,則在請(qǐng)求時(shí)創(chuàng)建屬性一樣容易。
無論如何,創(chuàng)建UICollectionViewLayoutAttributes
類的新實(shí)例時(shí),請(qǐng)使用以下類方法之一:
layoutAttributesForCellWithIndexPath:
layoutAttributesForSupplementaryViewOfKind:withIndexPath:
layoutAttributesForDecorationViewOfKind:withIndexPath:
你必須根據(jù)正在顯示的視圖類型使用正確的類方法,因?yàn)榧弦晥D使用該信息從數(shù)據(jù)源對(duì)象請(qǐng)求恰當(dāng)類型的視圖。使用錯(cuò)誤的方法會(huì)導(dǎo)致集合視圖在錯(cuò)誤的地方創(chuàng)建錯(cuò)誤的視圖,并且你的布局不會(huì)按預(yù)期顯示。
創(chuàng)建每個(gè)屬性對(duì)象之后,為相應(yīng)視圖設(shè)置相關(guān)屬性。至少,設(shè)置視圖在布局中的大小和位置。在布局視圖重疊的情況下,為zIndex屬性分配一個(gè)值,以確保重疊視圖的順序一致。其他屬性讓你控制單元格或視圖的可見性或外觀,并可以根據(jù)需要進(jìn)行更改。如果標(biāo)準(zhǔn)的屬性類不適合你的應(yīng)用程序需要,你可以子類化并且擴(kuò)展它以儲(chǔ)存關(guān)于每個(gè)視圖的其他信息。在子類化布局屬性時(shí),為了比較你的自定義屬性,必須實(shí)現(xiàn)isEqual:方法,因?yàn)榧弦晥D對(duì)其某些操作會(huì)使用此方法。
關(guān)于布局屬性的更多信息,請(qǐng)看UICollectionViewLayoutAttributes Class Reference。
準(zhǔn)備布局
在布局周期開始時(shí),布局對(duì)象會(huì)在布局過程開始前調(diào)用prepareLayout
方法。該方法給你一個(gè)機(jī)會(huì)來計(jì)算稍后通知你的布局的信息。實(shí)現(xiàn)自定義布局不是必須使用prepareLayout
方法,但是如果需要,可以作為進(jìn)行初始計(jì)算的機(jī)會(huì)。在該方法調(diào)用之后,你的布局必須具有足夠的信息來計(jì)算集合視圖內(nèi)容的大小,即布局過程的下一步。然而,該信息可以從這個(gè)最低要求到創(chuàng)建和存儲(chǔ)布局將使用的所有布局屬性對(duì)象。使用prepareLayout
方法需要你的應(yīng)用程序的基礎(chǔ)架構(gòu),以及有意義于計(jì)算前面和計(jì)算要求。關(guān)于prepareLayout
方法的示例,請(qǐng)看Preparing the Layout.
為給定矩形中的items提供布局屬性
在布局過程的最后一步時(shí),集合視圖調(diào)用你的布局對(duì)象的layoutAttributesForElementsInRect:
方法。該方法的目的是為與指定矩形相交的每個(gè)單元格和每個(gè)補(bǔ)充視圖或裝飾視圖提供布局屬性。對(duì)于一個(gè)大的滾動(dòng)內(nèi)容區(qū)域,集合視圖可能只是詢問當(dāng)前可見的內(nèi)容區(qū)域部分中的items
的屬性。在圖5-2中,你的布局對(duì)象需要?jiǎng)?chuàng)建屬性對(duì)象為當(dāng)前可見內(nèi)容是單元格6到20以及第二個(gè)標(biāo)題視圖。你必須準(zhǔn)備為集合視圖的內(nèi)容區(qū)域的任何部分提供布局屬性。這些屬性可能用于促進(jìn)插入或刪除items
的動(dòng)畫。
因?yàn)?code>layoutAttributesForElementsInRect:方法是在你的布局對(duì)象的prepareLayout
方法之后調(diào)用, 你應(yīng)該已經(jīng)擁有大部分信息,以返回或創(chuàng)建必需的屬性。你的layoutAttributesForElementsInRect:
方法的執(zhí)行遵循以下步驟:
- 迭代由
prepareLayout
方法生成的數(shù)據(jù),以訪問緩存的屬性或創(chuàng)建新的屬性。 - 檢查每個(gè)
item
的frame
, 看看它是否與傳遞給layoutAttributesForElementsInRect:
方法的矩形相交。 - 對(duì)于每個(gè)相交的
item
,將相應(yīng)的UICollectionViewLayoutAttributes
對(duì)象添加到數(shù)組。 - 返回布局屬性數(shù)組給集合視圖
根據(jù)你如何管理布局信息,你可以在prepareLayout
方法中創(chuàng)建UICollectionViewLayoutAttributes
對(duì)象,或者在layoutAttributesForElementsInRect
方法中執(zhí)行此操作。在形成符合應(yīng)用程序需求的實(shí)現(xiàn)時(shí),請(qǐng)牢記緩存布局信息的好處。為單元格重復(fù)計(jì)算新的布局屬性是一項(xiàng)昂貴的操作,可能會(huì)對(duì)應(yīng)用程序的性能造成明顯的不利影響。也就是說,當(dāng)你的集合視圖管理的items
數(shù)目很大時(shí),在請(qǐng)求時(shí)創(chuàng)建布局屬性可能會(huì)更有意義(針對(duì)性能)。這只是一個(gè)問題,弄清楚哪個(gè)策略對(duì)你的應(yīng)用程序來說是最有意義的。
注意:布局對(duì)象還需要能夠根據(jù)個(gè)別
items
提供布局屬性。集合視圖可能出于一些原因請(qǐng)求常規(guī)布局過程之外的信息,包括創(chuàng)建適當(dāng)?shù)膭?dòng)畫。有關(guān)按需提供布局屬性的詳細(xì)信息,請(qǐng)看Providing Layout Attributes On Demand
對(duì)于如何實(shí)現(xiàn)layoutAttributesForElementsInRect:
的具體示例,請(qǐng)看Providing Layout Attributes.
按需提供布局屬性
集合視圖定期詢問你的布局對(duì)象為正式布局過程之外的各個(gè)items
提供屬性。例如,集合視圖當(dāng)為一個(gè)item
配置插入和刪除動(dòng)畫時(shí)詢問這些信息。你的布局對(duì)象必須準(zhǔn)備為每個(gè)單元格、補(bǔ)充視圖和其支持的裝飾視圖提供布局屬性。你通過重寫下列方法來做這些:
layoutAttributesForItemAtIndexPath:
layoutAttributesForSupplementaryViewOfKind:atIndexPath:
layoutAttributesForDecorationViewOfKind:atIndexPath:
你的這些方法的實(shí)現(xiàn)應(yīng)該為給定的單元格或視圖獲取當(dāng)前的布局屬性。每個(gè)自定義布局對(duì)象都被預(yù)期實(shí)現(xiàn)layoutAttributesForItemAtIndexPath:
方法。如果你的布局不包含任何補(bǔ)充視圖,你不需要重寫layoutAttributesForSupplementaryViewOfKind:atIndexPath:
方法。相同的,如果你的布局不包含裝飾視圖,不需要重寫layoutAttributesForDecorationViewOfKind:atIndexPath:
方法。當(dāng)返回屬性時(shí),你不應(yīng)該更新布局屬性。如果你需要改變布局信息,無效化布局對(duì)象,并讓它在隨后的布局周期中更新數(shù)據(jù)。
連接自定義布局供使用
有兩種方式來關(guān)聯(lián)自定義布局到集合視圖:以編程方式或通過故事板。集合視圖通過一個(gè)可寫的屬性collectionViewLayout
來關(guān)聯(lián)它的布局。要將布局設(shè)置為自定義實(shí)現(xiàn),請(qǐng)將集合視圖的布局屬性設(shè)置為自定義布局對(duì)象的實(shí)例。清單5-1顯示所需的代碼行。
清單5-1 關(guān)聯(lián)自定義布局
self.collectionView.collectionViewLayout = [[MyCustomLayout alloc] init];
否則,從你的故事板,打開“文檔大綱”面板并選擇你的集合視圖(它列在控制器的下拉菜單中)。選擇集合視圖后,在“實(shí)用程序”窗口打開“屬性”檢查器,并在標(biāo)簽有集合視部分的下方將“布局”選項(xiàng)從“流式”改成“自定義”。它下面的選項(xiàng)從滾動(dòng)方向更改為類,現(xiàn)在可以選擇自定義布局類。
使你的自定義布局更具吸引力
在布局過程中為每個(gè)單元格和視圖提供布局屬性是必需的,但是用你的自定義布局有其他的行為可以提高用戶體驗(yàn)。實(shí)現(xiàn)這些行為是可選的但推薦使用。
通過補(bǔ)充視圖提高內(nèi)容
補(bǔ)充視圖是與集合視圖的單元格分離開來的,并有它自己的布局屬性集合。和單元格一樣,這些視圖被數(shù)據(jù)源對(duì)象提供,但是它們的目的是來增強(qiáng)應(yīng)用程序的主要內(nèi)容。例如,UICollectionViewFlowLayout
為分區(qū)頭和分區(qū)尾來使用補(bǔ)充視圖。另一個(gè)應(yīng)用程序可以使用補(bǔ)充視圖來給每個(gè)單元格自定的文本標(biāo)簽來顯示關(guān)于該單元格的信息。和集合視圖單元格一樣,補(bǔ)充視圖有回收機(jī)制,以優(yōu)化集合視圖所使用的資源數(shù)量。因此,在你的應(yīng)用程序中使用的所有補(bǔ)充視圖,都應(yīng)該繼承自UICollectionReusableView
類。
將補(bǔ)充視圖添加到布局的步驟如下:
- 使用
registerClass:forSupplementaryViewOfKind:withReuseIdentifier:
或registerNib:forSupplementaryViewOfKind:withReuseIdentifier:
方法注冊(cè)補(bǔ)充視圖到集合視圖的布局對(duì)象 - 在你的數(shù)據(jù)源中,實(shí)現(xiàn)
collectionView:viewForSupplementaryElementOfKind:atIndexPath:
方法。因?yàn)檫@些視圖是重用的,調(diào)用dequeueReusableSupplementaryViewOfKind:withReuseIdentifier:forIndexPath:
來獲取,或者創(chuàng)建一個(gè)新的重用視圖,并在返回前設(shè)置必要的數(shù)據(jù)。 - 為你的補(bǔ)充視圖創(chuàng)建布局屬性,就像為單元格做這些一樣。
- 通過
layoutAttributesForElementsInRect:
方法返回一個(gè)數(shù)組,該數(shù)組包含這些布局屬性對(duì)象。 - 實(shí)現(xiàn)
layoutAttributesForSupplementaryViewOfKind:atIndexPath:
方法為特定補(bǔ)充視圖每當(dāng)查詢時(shí)返回屬性對(duì)象。
在自定義布局中為補(bǔ)充視圖創(chuàng)建屬性對(duì)象的過程是幾乎與單元格的過程相同,不同之處在于自定義布局可以有多種類型的補(bǔ)充視圖,而單元格的類型限制為一種。這是因?yàn)檠a(bǔ)充視圖旨在增強(qiáng)主要內(nèi)容,因此與它分離。有許多方法可以補(bǔ)充應(yīng)用程序的內(nèi)容,因此每個(gè)補(bǔ)充視圖的方法都會(huì)指定要處理哪種視圖以區(qū)分其他視圖,并允許布局根據(jù)其類型正確計(jì)算其屬性。當(dāng)注冊(cè)一個(gè)補(bǔ)充視圖來使用時(shí),你提供使用的字符串通過布局對(duì)象來區(qū)分來自于其他的視圖。有關(guān)將補(bǔ)充視圖合并到自定義布局中的示例,請(qǐng)看Incorporating Supplementary Views
在自定義布局中包含裝飾視圖
裝飾視圖是增強(qiáng)集合視圖布局外觀的視覺裝飾。不像單元格和補(bǔ)充視圖,裝飾視圖僅提供可視內(nèi)容,因此獨(dú)立于數(shù)據(jù)源。你可以使用它們來提供自定義背景,填充單元格之間的空間,或者甚至模糊你想要的單元格。裝飾視圖僅由布局對(duì)象定義和管理,不與集合視圖的數(shù)據(jù)源對(duì)象交互。
要將裝飾視圖添加到布局中,請(qǐng)執(zhí)行以下操作:
- 使用
registerClass:forDecorationViewOfKind:
或registerNib:forDecorationViewOfKind:
方法使用布局對(duì)象注冊(cè)你的裝飾視圖。雖然這個(gè)過程有點(diǎn)像注冊(cè)單元格和補(bǔ)充視圖,但記住注冊(cè)裝飾視圖是發(fā)生在布局對(duì)象上,而與數(shù)據(jù)源無關(guān)。 - 在你的布局對(duì)象的
layoutAttributesForElementsInRect:
方法中,為裝飾視圖創(chuàng)建屬性,就像為單元格和補(bǔ)充視圖那樣做一樣。 - 在你的布局對(duì)象中實(shí)現(xiàn)
layoutAttributesForDecorationViewOfKind:atIndexPath:
方法,并當(dāng)詢問時(shí)返回裝飾視圖的屬性。 - 可選的,實(shí)現(xiàn)
initialLayoutAttributesForAppearingDecorationElementOfKind:atIndexPath:
和finalLayoutAttributesForDisappearingDecorationElementOfKind:atIndexPath:
方法來處理動(dòng)畫為裝飾視圖的出現(xiàn)和消失。關(guān)于更多信息,請(qǐng)看Making Insertion and Deletion Animations More Interesting
創(chuàng)建裝飾視圖的過程與單元格和補(bǔ)充視圖的過程不同。注冊(cè)類或nib文件是需要做的,以確保在需要的時(shí)候創(chuàng)建裝飾視圖。因?yàn)樗鼈兗兇馐且曈X的,裝飾視圖不需要超出在提供的nib文件或?qū)ο蟮?code>initWithFrame:方法中已經(jīng)完成的任何配置。因此,當(dāng)需要裝飾視圖時(shí),集合視圖為你創(chuàng)建并應(yīng)用布局對(duì)象提供的屬性。任何裝飾視圖都應(yīng)該繼承自UICollectionReusableView
,因?yàn)椴季謱?duì)象使用其裝飾視圖的回收機(jī)制。
注意:當(dāng)為你的裝飾視圖創(chuàng)建屬性時(shí),不要忘記考慮
zIndex
屬性。你可以使用zIndex
屬性將顯示的單元格和補(bǔ)充視圖背后(或者,如果你愿意的話)層疊你的裝飾視圖。
使插入和刪除動(dòng)畫更有趣
插入和刪除單元格和視圖在布局過程中構(gòu)成了一個(gè)有趣的挑戰(zhàn)。插入單元格可能會(huì)導(dǎo)致其他單元格和視圖的布局更改。即使布局對(duì)象知道如何將現(xiàn)有單元格和視圖從當(dāng)前位置設(shè)置為新位置,但它沒有插入單元格的當(dāng)前位置。代替插入一個(gè)新的單元格沒有動(dòng)畫效果,集合視圖會(huì)詢問布局對(duì)象來提供一組用于動(dòng)畫的初始屬性。相似的,當(dāng)單元格被刪除時(shí),集合視圖會(huì)詢問布局對(duì)象來提供用于任何動(dòng)畫的端點(diǎn)的一組最終屬性。
為了理解初始屬性的工作原理,可以看一個(gè)示例。起始布局(圖5-3)顯示了最初只包含三個(gè)單元格的集合視圖。當(dāng)一個(gè)新的單元格被插入時(shí),集合視圖會(huì)詢問布局對(duì)象來提供初始屬性為被插入的單元格。在這種情況下,布局對(duì)象會(huì)將單元格的起始位置設(shè)置在集合視圖的中心,并設(shè)置它的透明度值為0來隱藏它。在動(dòng)畫期間,這個(gè)新單元格會(huì)淡出并從集合視圖的中心移動(dòng)到右下角的最終位置。
清單5-2顯示了如圖5-3所示可以用來指定插入單元格的初始屬性的代碼。此方法將單元格的位置設(shè)置為集合視圖的中心,并使其透明。然后,布局對(duì)象將作為常規(guī)布局過程的一部分,為單元格提供最終位置和alpha
值。
清單5-2 指定插入單元格的初始屬性
- (UICollectionViewLayoutAttributes *)initialLayoutAttributesForAppearingItemAtIndexPath:(NSIndexPath *)itemIndexPath {
UICollectionViewLayoutAttributes* attributes = [self layoutAttributesForItemAtIndexPath:itemIndexPath];
attributes.alpha = 0.0;
CGSize size = [self collectionView].frame.size;
attributes.center = CGPointMake(size.width / 2.0, size.height / 2.0);
return attributes;
}
注意:列表5-2將在插入一個(gè)單元格時(shí)對(duì)所有單元格進(jìn)行動(dòng)畫處理,因此在插入之前已經(jīng)存在的三個(gè)單元格也將從集合視圖的中心彈出。要僅動(dòng)畫所插入的單元格,請(qǐng)檢查item的索引路徑是否與傳遞給
prepareForCollectionViewUpdates:
方法的item
的索引路徑匹配,并且僅在找到匹配項(xiàng)時(shí)才執(zhí)行動(dòng)畫。否則,返回通過調(diào)用initialLayoutAttributesForAppearingItemAtIndexPath
的super
方法返回的屬性。
處理刪除的過程與插入過程相同,只是您指定最終屬性而不是初始屬性。從上一個(gè)示例中,如果您使用與插入單元格時(shí)使用的相同的屬性,則刪除單元格將導(dǎo)致它在移動(dòng)到集合視圖的中心時(shí)淡出。在UICollectionViewLayout
類中有六種方法可用于item
,補(bǔ)充視圖和裝飾視圖的兩個(gè)獨(dú)立方法(初始和最終屬性)。
改善布局的滾動(dòng)體驗(yàn)
自定義布局對(duì)象可以影響集合視圖的滾動(dòng)行為,以創(chuàng)建更好的用戶體驗(yàn)。當(dāng)滾動(dòng)相關(guān)觸摸事件結(jié)束時(shí),滾動(dòng)視圖根據(jù)當(dāng)前的實(shí)際速度和減速率確定滾動(dòng)內(nèi)容的最終靜止位置。當(dāng)集合視圖知道該位置時(shí),如果位置應(yīng)該被改變它會(huì)詢問布局對(duì)象通過調(diào)用它的targetContentOffsetForProposedContentOffset:withScrollingVelocity:
方法。因?yàn)樗诨A(chǔ)內(nèi)容仍然移動(dòng)時(shí)調(diào)用此方法,自定義布局可能會(huì)影響滾動(dòng)內(nèi)容的最終位置。
圖5-4演示了如何使用布局對(duì)象來更改集合視圖的滾動(dòng)行為。假設(shè)集合視圖偏移從(0,0)開始,用戶向左滑動(dòng)。集合視圖計(jì)算滾動(dòng)自然停止的位置,并將該值提供為“建議”內(nèi)容偏移值。您的布局對(duì)象可能會(huì)更改建議值,以確保在滾動(dòng)停止時(shí),item將精確集中在集合視圖的可見邊界。這個(gè)新值將成為目標(biāo)內(nèi)容偏移,并且時(shí)從targetContentOffsetForProposedContentOffset:withScrollingVelocity:
返回。
實(shí)現(xiàn)自定義布局的提示
以下是實(shí)現(xiàn)自定義布局對(duì)象的一些提示和建議:
- 考慮使用
prepareLayout
方法來創(chuàng)建和存儲(chǔ)以后需要的UICollectionViewLayoutAttributes
對(duì)象。集合視圖將在某個(gè)時(shí)候詢問布局屬性對(duì)象,因此在某些情況下,可以在前面創(chuàng)建和存儲(chǔ)它們。如果您的items
數(shù)量相對(duì)較少(幾百個(gè))或這些items
的實(shí)際布局屬性不會(huì)頻繁更改,則尤其如此。但是,如果您的布局需要管理數(shù)千個(gè)items
,則需要權(quán)衡緩存和重新計(jì)算的優(yōu)勢(shì)。對(duì)于其布局不經(jīng)常更改的可變大小items
,緩存通常不需要定期重新計(jì)算復(fù)雜的布局信息。對(duì)于大量固定大小的items
,可以根據(jù)需要計(jì)算屬性更簡(jiǎn)單。而對(duì)于屬性頻繁更改的items
,您可能會(huì)重新計(jì)算所有時(shí)間,因此緩存可能只占用內(nèi)存中的額外空間。 - 避免子類化
UICollectionView
。集合視圖有很少或沒有自己的外觀。相反,它從數(shù)據(jù)源對(duì)象和布局對(duì)象的所有布局相關(guān)信息中提取其所有視圖。如果您嘗試在三維中布置items
,正確的方法是實(shí)現(xiàn)一個(gè)自定義布局,以便設(shè)置每個(gè)單元格的3D變換并正確查看。 - 不要從您的自定義布局對(duì)象的
layoutAttributesForElementsInRect:
方法調(diào)用UICollectionView
的visibleCells
方法。集合視圖對(duì)于items
的位置一無所知,除非布局對(duì)象告訴它。所以詢問可見單元格只是將請(qǐng)求轉(zhuǎn)發(fā)到你的布局對(duì)象上。您的布局對(duì)象應(yīng)始終知道內(nèi)容區(qū)域中items
的位置,并且可以隨時(shí)返回這些items
的屬性。在大多數(shù)情況下,它應(yīng)該自己做。在有限的情況下,布局對(duì)象可能依賴于數(shù)據(jù)源中的信息來定位items
。例如,在地圖上顯示items
的布局可能會(huì)從數(shù)據(jù)源中檢索每個(gè)item
的地圖位置。
官方文檔地址
Creating Custom Layouts