文檔翻譯-Collection View - 1.5

創(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)用這些方法:

  1. 使用prepareLayout方法來執(zhí)行提供布局信息所需的前期計(jì)算。
  2. 使用collectionViewContentSize方法來根據(jù)初始計(jì)算返回整個(gè)內(nèi)容區(qū)域的總體大小。
  3. 使用layoutAttributesForElementsInRect:方法來返回指定矩形中的單元格和視圖的屬性。

圖5-1 說明如何使用上述方法生成布局信息

圖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)使用以下類方法之一:

  1. layoutAttributesForCellWithIndexPath:
  2. layoutAttributesForSupplementaryViewOfKind:withIndexPath:
  3. 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)畫。

圖5-2

因?yàn)?code>layoutAttributesForElementsInRect:方法是在你的布局對(duì)象的prepareLayout方法之后調(diào)用, 你應(yīng)該已經(jīng)擁有大部分信息,以返回或創(chuàng)建必需的屬性。你的layoutAttributesForElementsInRect:方法的執(zhí)行遵循以下步驟:

  1. 迭代由prepareLayout方法生成的數(shù)據(jù),以訪問緩存的屬性或創(chuàng)建新的屬性。
  2. 檢查每個(gè)itemframe, 看看它是否與傳遞給layoutAttributesForElementsInRect:方法的矩形相交。
  3. 對(duì)于每個(gè)相交的item,將相應(yīng)的UICollectionViewLayoutAttributes對(duì)象添加到數(shù)組。
  4. 返回布局屬性數(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ǔ)充視圖和其支持的裝飾視圖提供布局屬性。你通過重寫下列方法來做這些:

  1. layoutAttributesForItemAtIndexPath:
  2. layoutAttributesForSupplementaryViewOfKind:atIndexPath:
  3. 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ǔ)充視圖添加到布局的步驟如下:

  1. 使用registerClass:forSupplementaryViewOfKind:withReuseIdentifier:registerNib:forSupplementaryViewOfKind:withReuseIdentifier:方法注冊(cè)補(bǔ)充視圖到集合視圖的布局對(duì)象
  2. 在你的數(shù)據(jù)源中,實(shí)現(xiàn)collectionView:viewForSupplementaryElementOfKind:atIndexPath:方法。因?yàn)檫@些視圖是重用的,調(diào)用dequeueReusableSupplementaryViewOfKind:withReuseIdentifier:forIndexPath:來獲取,或者創(chuàng)建一個(gè)新的重用視圖,并在返回前設(shè)置必要的數(shù)據(jù)。
  3. 為你的補(bǔ)充視圖創(chuàng)建布局屬性,就像為單元格做這些一樣。
  4. 通過layoutAttributesForElementsInRect:方法返回一個(gè)數(shù)組,該數(shù)組包含這些布局屬性對(duì)象。
  5. 實(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í)行以下操作:

  1. 使用registerClass:forDecorationViewOfKind:registerNib:forDecorationViewOfKind:方法使用布局對(duì)象注冊(cè)你的裝飾視圖。雖然這個(gè)過程有點(diǎn)像注冊(cè)單元格和補(bǔ)充視圖,但記住注冊(cè)裝飾視圖是發(fā)生在布局對(duì)象上,而與數(shù)據(jù)源無關(guān)。
  2. 在你的布局對(duì)象的layoutAttributesForElementsInRect:方法中,為裝飾視圖創(chuàng)建屬性,就像為單元格和補(bǔ)充視圖那樣做一樣。
  3. 在你的布局對(duì)象中實(shí)現(xiàn)layoutAttributesForDecorationViewOfKind:atIndexPath:方法,并當(dāng)詢問時(shí)返回裝飾視圖的屬性。
  4. 可選的,實(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-3

清單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)用initialLayoutAttributesForAppearingItemAtIndexPathsuper方法返回的屬性。

處理刪除的過程與插入過程相同,只是您指定最終屬性而不是初始屬性。從上一個(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:返回。

圖5-4

實(shí)現(xiàn)自定義布局的提示

以下是實(shí)現(xiàn)自定義布局對(duì)象的一些提示和建議:

  1. 考慮使用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)存中的額外空間。
  2. 避免子類化UICollectionView。集合視圖有很少或沒有自己的外觀。相反,它從數(shù)據(jù)源對(duì)象和布局對(duì)象的所有布局相關(guān)信息中提取其所有視圖。如果您嘗試在三維中布置items,正確的方法是實(shí)現(xiàn)一個(gè)自定義布局,以便設(shè)置每個(gè)單元格的3D變換并正確查看。
  3. 不要從您的自定義布局對(duì)象的layoutAttributesForElementsInRect:方法調(diào)用UICollectionViewvisibleCells方法。集合視圖對(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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,321評(píng)論 6 543
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,559評(píng)論 3 429
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,442評(píng)論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,835評(píng)論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,581評(píng)論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,922評(píng)論 1 328
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,931評(píng)論 3 447
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 43,096評(píng)論 0 290
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,639評(píng)論 1 336
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,374評(píng)論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,591評(píng)論 1 374
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,104評(píng)論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,789評(píng)論 3 349
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,196評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,524評(píng)論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,322評(píng)論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,554評(píng)論 2 379

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