文檔翻譯-Collection View - 1.6

自定義布局:一個(gè)樣例

創(chuàng)建直觀的自定義集合視圖布局是簡(jiǎn)單的礁蔗,但是流程的實(shí)現(xiàn)細(xì)節(jié)可能會(huì)有所不同。你的布局必須為你的集合視圖包含的所有視圖生產(chǎn)布局屬性對(duì)象雁社。創(chuàng)建這些屬性的順序取決于應(yīng)用程序的性質(zhì)瘦麸。一個(gè)集合視圖,包含數(shù)千個(gè)items歧胁,在前期計(jì)算和緩存布局屬性是一個(gè)耗時(shí)的過(guò)程滋饲,所以只在特定的item請(qǐng)求時(shí)創(chuàng)建屬性才更有意義。對(duì)于應(yīng)用程序包含比較少的items時(shí)喊巍,一次性計(jì)算布局信息并在請(qǐng)求屬性時(shí)緩存它為引用可以保存你的應(yīng)用程序大部分不必要的計(jì)算屠缭。本章中的樣例屬于第二類。
請(qǐng)記住崭参,提供的樣例代碼并不是創(chuàng)建一個(gè)自定義布局的最終方式呵曹。在你開(kāi)始創(chuàng)建你的自定義布局之前,花時(shí)間設(shè)計(jì)一個(gè)實(shí)現(xiàn)結(jié)構(gòu),使你的應(yīng)用程序更有意義以獲取最好的性能奄喂。關(guān)于布局自定義化過(guò)程概念性概述铐殃,請(qǐng)看Creating Custom Layouts
因?yàn)楸菊乱蕴囟ǖ捻樞蚪榻B自定義布局實(shí)現(xiàn)跨新,沿著實(shí)例從上到下富腊,記住一個(gè)具體的實(shí)現(xiàn)目標(biāo)。本章關(guān)注于創(chuàng)建自定義布局域帐,不是一個(gè)完整應(yīng)用程序的實(shí)現(xiàn)赘被。因此,用來(lái)創(chuàng)建最終產(chǎn)品的視圖和控制器的實(shí)現(xiàn)是沒(méi)有提供的肖揣。布局使用自定義集合視圖的單元格作為其單元格民假,并創(chuàng)建用于將單元格連接到另一單元格的自定義視圖。為集合視圖創(chuàng)建自定義單元格和視圖龙优,以及使用集合視圖的要求羊异,在前面的章節(jié)中都有介紹。要回顧這些信息彤断,請(qǐng)看Collection View BasicsDesigning Your Data Source and Delegate球化。

概念

這個(gè)樣例的目的是實(shí)現(xiàn)一個(gè)自定義布局來(lái)顯示信息的層級(jí)結(jié)構(gòu)樹(shù),如圖6-1所示瓦糟。該示例提供代碼片段筒愚,然后對(duì)代碼進(jìn)行說(shuō)明,以及您已達(dá)到的定制過(guò)程中的要點(diǎn)菩浙。集合視圖的每個(gè)部分構(gòu)成樹(shù)的一個(gè)深度級(jí)別:第0節(jié)僅包含NSObject單元格巢掺。第1節(jié)包含NSObject的所有子單元格。第2節(jié)包含這些子單元格的所有子單元格劲蜻,等等陆淀。每個(gè)單元格是一個(gè)自定義單元格,具有關(guān)聯(lián)類名稱的標(biāo)簽先嬉,單元格之間的連接是補(bǔ)充視圖轧苫。因?yàn)檫B接器視圖類必須確定要繪制的連接數(shù),所以需要訪問(wèn)數(shù)據(jù)源中的數(shù)據(jù)疫蔓。因此含懊,將這些連接作為補(bǔ)充視圖而不是裝飾視圖是有意義的。

圖6-1
初始化

創(chuàng)建自定義布局的第一步是將UICollectionViewLayout類子類化衅胀。這樣做為您提供構(gòu)建自定義布局所需的基礎(chǔ)岔乔。
對(duì)于此示例,需要自定義協(xié)議來(lái)通知在某些items之間布局的間距滚躯。如果特定items的屬性需要數(shù)據(jù)源的額外信息雏门,則最好為自定義布局實(shí)現(xiàn)協(xié)議嘿歌,而不是啟動(dòng)與數(shù)據(jù)源的直接連接。您所產(chǎn)生的布局更加強(qiáng)大和可重用; 它不會(huì)附加到特定的數(shù)據(jù)源茁影,而是會(huì)響應(yīng)實(shí)現(xiàn)其協(xié)議的任何對(duì)象宙帝。
清單6-1顯示了自定義布局頭文件的必要代碼。 現(xiàn)在募闲,任何實(shí)現(xiàn)MyCustomProtocol協(xié)議的類都可以使用自定義布局步脓,布局可以查詢?cè)擃愃璧男畔ⅰ?br> 清單6-1 連接到自定義協(xié)議

@interface MyCustomLayout: UICollectionViewLayout

@property (nonatomic, weak) id<MyCustomProtocol> customDataSource;

@end

接下來(lái),因?yàn)榧弦晥D將管理的items數(shù)量相對(duì)較低蝇更,所以自定義布局使用緩存系統(tǒng)來(lái)存儲(chǔ)在準(zhǔn)備布局時(shí)生成的布局屬性,然后每當(dāng)集合視圖詢問(wèn)它們時(shí)檢索這些存儲(chǔ)的值呼盆。清單6-2顯示了我們的布局將需要維護(hù)的三個(gè)私有屬性和init方法年扩。 layoutInformation字典包含我們的集合視圖中所有類型的視圖的所有布局屬性,maxNumRows屬性跟蹤需要多少行來(lái)填充我們樹(shù)的最高列访圃。insets對(duì)象控制單元格之間的間距厨幻,并用于設(shè)置視圖的frames和內(nèi)容大小。前兩個(gè)屬性的值在準(zhǔn)備布局時(shí)設(shè)置腿时,但是應(yīng)該使用init方法設(shè)置insets對(duì)象况脆。在這種情況下,INSET_TOP批糟,INSET_LEFT格了,INSET_BOTTOMINSET_RIGHT是指為每個(gè)參數(shù)定義的常量。
清單6-2. 初始化變量

@interface MyCustomLayout()

@property (nonatomic) NSDictionary *layoutInformation;
@property (nonatomic) NSInteger maxNumRows;
@property (nonatomic) UIEdgeInsets insets;

@end

-(id)init {
    if(self = [super init]) {
        self.insets = UIEdgeInsetsMake(INSET_TOP, INSET_LEFT, INSET_BOTTOM, INSET_RIGHT);
    }
    return self;
}

此自定義布局的最后一步是創(chuàng)建自定義布局屬性徽鼎。雖然此步驟并不總是必需的盛末,但在這種情況下,當(dāng)單元格被放置時(shí)否淤,代碼需要訪問(wèn)當(dāng)前單元格的子項(xiàng)的索引路徑悄但,以便它可以調(diào)整子單元格的frames以匹配其父元素的。所以子類化UICollectionViewLayoutAttributes來(lái)存儲(chǔ)一個(gè)單元格的子元素的數(shù)組提供的信息石抡。您的子類UICollectionViewLayoutAttributes檐嚣,并在頭文件中添加以下代碼:

@property (nonatomic) NSArray *children;

UICollectionViewLayoutAttributes類引用所述,子類化布局屬性要求您在iOS 7及更高版本中覆蓋繼承的isEqual:方法啰扛。有關(guān)為何要這樣做的更多信息嚎京,請(qǐng)看UICollectionViewLayoutAttributes Class Reference
在這種情況下隐解,isEqual:方法的實(shí)現(xiàn)很簡(jiǎn)單挖藏,因?yàn)橹挥幸粋€(gè)字段來(lái)比較 - 子數(shù)組的內(nèi)容。如果兩個(gè)布局屬性對(duì)象的數(shù)組匹配厢漩,則它們必須相等膜眠,因?yàn)樽宇愔荒軐儆谝粋€(gè)類。清單6-3顯示了isEqual:方法的實(shí)現(xiàn)。
清單6-3 實(shí)現(xiàn)子類化布局屬性的要求

-(BOOL)isEqual:(id)object {
    MyCustomAttributes *otherAttributes = (MyCustomAttributes *)object;
    if ([self.children isEqualToArray:otherAttributes.children]) {
        return [super isEqual:object];
    }
    return NO;
}

請(qǐng)記住在自定義布局文件中包含自定義布局屬性的頭文件宵膨。

在此過(guò)程中架谎,您已準(zhǔn)備好開(kāi)始實(shí)現(xiàn)自定義布局的主要部分,其中包含您所基于的基礎(chǔ)辟躏。

準(zhǔn)備布局

現(xiàn)在谷扣,所有必要的組件都已初始化,您可以準(zhǔn)備布局捎琐。集合視圖在布局過(guò)程中首先調(diào)用prepareLayout方法会涎。在此示例中,prepareLayout方法用于實(shí)例化集合視圖中每個(gè)視圖的所有布局屬性對(duì)象瑞凑,然后將這些屬性緩存在我們的layoutInformation字典中末秃,以供以后使用。有關(guān)prepareLayout方法的更多信息籽御,請(qǐng)參閱Preparing the Layout练慕。

創(chuàng)建布局屬性

prepareLayout方法的示例實(shí)現(xiàn)分為兩部分。圖6-2顯示了上半部分方法的目標(biāo)技掏。代碼遍歷每個(gè)單元格铃将,如果該單元格有子元素,則將這些子元素與父單元格相關(guān)聯(lián)哑梳。從圖中可以看出劲阎,這個(gè)過(guò)程是針對(duì)每個(gè)單元格進(jìn)行的,包括其他父單元格的子單元格鸠真。

圖6-2

清單6-4顯示了prepareLayout方法實(shí)現(xiàn)的前半部分哪工。在代碼開(kāi)頭初始化的兩個(gè)可變字典構(gòu)成緩存機(jī)制的基礎(chǔ)。首先弧哎,layoutInformation雁比,是layoutInformation屬性的本地等價(jià)物。創(chuàng)建局部可變副本允許實(shí)例變量是不可變的撤嫩,這在自定義布局的實(shí)現(xiàn)中是有意義的偎捎,因?yàn)樵?code>prepareLayout方法完成運(yùn)行后不應(yīng)修改布局屬性。然后序攘,代碼以增加的順序遍歷每個(gè)部分茴她,然后遍歷每個(gè)部分中的每個(gè)item,以創(chuàng)建每個(gè)單元格的屬性程奠。自定義方法attributesWithChildrenForIndexPath:返回自定義布局屬性的實(shí)例丈牢,其中children屬性使用當(dāng)前索引路徑中item的子項(xiàng)的索引路徑填充。然后將屬性對(duì)象存儲(chǔ)在本地cellInformation字典中瞄沙,其索引路徑作為關(guān)鍵字己沛。初始通過(guò)所有items允許代碼在設(shè)置itemframe之前為每個(gè)item設(shè)置子項(xiàng)慌核。

清單6-4 創(chuàng)建布局屬性

- (void)prepareLayout {
    NSMutableDictionary *layoutInformation = [NSMutableDictionary dictionary];
    NSMutableDictionary *cellInformation = [NSMutableDictionary dictionary];
    NSIndexPath *indexPath;
    NSInteger numSections = [self.collectionView numberOfSections;]
    for(NSInteger section = 0; section < numSections; section++){
        NSInteger numItems = [self.collectionView numberOfItemsInSection:section];
        for(NSInteger item = 0; item < numItems; item++){
            indexPath = [NSIndexPath indexPathForItem:item inSection:section];
            MyCustomAttributes *attributes =
            [self attributesWithChildrenAtIndexPath:indexPath];
            [cellInformation setObject:attributes forKey:indexPath];
        }
    }
    //end of first section
存儲(chǔ)布局屬性

圖6-3描述了在PrepareLayout方法的后半部分中發(fā)生的進(jìn)程,其中從最后一行構(gòu)建樹(shù)層次結(jié)構(gòu)到第一行申尼。這種方法起初看起來(lái)很奇特垮卓,但它是調(diào)整子單元格的frames的復(fù)雜度的一種巧妙方法。因?yàn)楹⒆訂卧竦?code>frames需要與其父代的frames相匹配师幕,并且因?yàn)樾虚g排列的單元格之間的空間量取決于單元格有多少個(gè)子元素(包括每個(gè)子單元格有多少個(gè)子元素 等等)粟按,您要在設(shè)置父項(xiàng)之前設(shè)置子frame。以這種方式霹粥,可以調(diào)整子單元格及其所有子單元格灭将,使其與父單元格的整體相匹配。
在步驟1中后控,最后一列的單元格已按順序放置庙曙。在步驟2中,布局正在確定第二列的幀忆蚀。在這一列中矾利,單元格可以順序布置姑裂,因?yàn)闆](méi)有細(xì)胞有多于一個(gè)子單元格馋袜。然而,綠色單元格的frame必須調(diào)整為與其父單元格相匹配舶斧,因此它將向下移動(dòng)一個(gè)空格欣鳖。在最后一步中,放置第一列的單元格茴厉。第二列的前三個(gè)單元格是第一列中第一個(gè)單元格的子元素泽台,因此第一列中第一個(gè)單元格的單元格向下移動(dòng)。在這種情況下矾缓,實(shí)際上沒(méi)有必要這樣做怀酷,因?yàn)榈谝粋€(gè)后面的兩個(gè)單元格沒(méi)有自己的子項(xiàng),但布局對(duì)象不夠聰明才能知道這一點(diǎn)嗜闻。相反蜕依,它總是調(diào)整空間,以防任何與子元素有關(guān)的單元格具有自己的子元素琉雳。此外样眠,綠色單元格現(xiàn)在已經(jīng)向下移動(dòng)以匹配其父單元格。

圖6-3

清單6-5顯示了prepareLayout方法的下半部分翠肘,其中為每個(gè)item設(shè)置了frame檐束。以下代碼之后的注釋號(hào)碼對(duì)應(yīng)于代碼之后找到的編號(hào)說(shuō)明。
清單6-5 存儲(chǔ)布局屬性

 //continuation of prepareLayout implementation
    for(NSInteger section = numSections - 1; section >= 0; section—-){
        NSInteger numItems = [self.collectionView numberOfItemsInSection:section];
        NSInteger totalHeight = 0;
        for(NSInteger item = 0; item < numItems; item++){
            indexPath = [NSIndexPath indexPathForItem:item inSection:section];
            MyCustomAttributes *attributes = [cellInfo objectForKey:indexPath]; // 1
            attributes.frame = [self frameForCellAtIndexPath:indexPath
                            withHeight:totalHeight];
            [self adjustFramesOfChildrenAndConnectorsForClassAtIndexPath:indexPath]; // 2
            cellInfo[indexPath] = attributes;
            totalHeight += [self.customDataSource
                        numRowsForClassAndChildrenAtIndexPath:indexPath]; // 3
        }
        if(section == 0){
            self.maxNumRows = totalHeight; // 4
        }
    }
    [layoutInformation setObject:cellInformation forKey:@"MyCellKind"]; // 5
    self.layoutInformation = layoutInformation
}

在清單6-5中束倍,代碼以降序遍歷這些部分被丧,從后面到前面構(gòu)建樹(shù)盟戏。totalHeight變量跟蹤當(dāng)前項(xiàng)目所需的行數(shù)。這個(gè)實(shí)現(xiàn)并不能智能地跟蹤間隔晚碾,只需在小單元格之下留下空格抓半,使兩個(gè)單元格的子代不會(huì)重疊,而totalHeight變量有助于實(shí)現(xiàn)這一點(diǎn)格嘁。代碼按以下順序完成:

  1. 我們?cè)跀?shù)據(jù)的第一次傳遞中創(chuàng)建的布局屬性在單元格frame被設(shè)置之前從本地字典中檢索笛求。
  2. 自定義adjustFramesOfChildrenAndConnectorsForClassAtIndexPath:方法遞歸地調(diào)整所有單元格的子節(jié)點(diǎn)和子節(jié)點(diǎn)的frames等,以匹配單元格的frame糕簿。
  3. 將調(diào)整后的屬性返回到字典后探入,將調(diào)整totalHeight變量以反映下一個(gè)itemframe所在的位置。這是代碼利用自定義協(xié)議的地方懂诗。無(wú)論實(shí)現(xiàn)協(xié)議需要實(shí)現(xiàn)numRowsForClassAndChildrenAtIndexPath:方法的任何對(duì)象蜂嗽,它返回每個(gè)類需要占用多少行,因?yàn)樗卸嗌賯€(gè)子項(xiàng)殃恒。
  4. maxNumRows屬性(稍后需要設(shè)置內(nèi)容大兄簿伞)設(shè)置為0的總高度。具有最長(zhǎng)高度的列始終為0离唐,對(duì)于樹(shù)中的所有子項(xiàng)都進(jìn)行了高度調(diào)整病附,因?yàn)榇藢?shí)現(xiàn)不包括智能空間調(diào)整。
  5. 該方法的結(jié)論是將具有所有單元格屬性的字典插入到具有唯一字符串標(biāo)識(shí)符作為其關(guān)鍵字的本地layoutInformation字典中亥鬓。

在最后一步中用于插入字典的字符串標(biāo)識(shí)符用于整個(gè)自定義布局的其余部分完沪,以檢索單元格的正確屬性。當(dāng)補(bǔ)充視圖在示例中進(jìn)一步發(fā)揮作用時(shí)嵌戈,它就變得更為重要覆积。

提供內(nèi)容大小

在準(zhǔn)備布局時(shí),代碼將maxNumRows的值設(shè)置為布局中最大部分中的行數(shù)熟呛】淼担可以利用此信息設(shè)置適當(dāng)?shù)膬?nèi)容大小,這是布局過(guò)程的下一步庵朝。清單6-6顯示了CollectionViewContentSize的實(shí)現(xiàn)吗冤。它依賴于常量ITEM_WIDTHITEM_HEIGHT,這些常量可能是應(yīng)用程序的全局性(例如偿短,在自定義單元實(shí)現(xiàn)中需要正確設(shè)置單元格標(biāo)簽)欣孤。
清單6-6 調(diào)整內(nèi)容區(qū)域的大小

- (CGSize)collectionViewContentSize {
    CGFloat width = self.collectionView.numberOfSections * (ITEM_WIDTH + self.insets.left + self.insets.right);
    CGFloat height = self.maxNumRows * (ITEM_HEIGHT + _insets.top + _insets.bottom);
    return CGSizeMake(width, height);
}
提供布局屬性

將所有布局屬性對(duì)象初始化和緩存,代碼完全準(zhǔn)備好提供layoutAttributesForElementsInRect:方法中請(qǐng)求的所有布局信息昔逗。該方法是布局過(guò)程的第二步降传,與prepareLayout方法不同,它是必需的勾怒。該方法提供一個(gè)矩形婆排,并且期望一個(gè)布局屬性數(shù)組的數(shù)組声旺,用于包含在提供的矩形內(nèi)的任何視圖。在某些情況下段只,有數(shù)千個(gè)items的集合視圖可能會(huì)等到此方法被調(diào)用以初始化布局屬性對(duì)象腮猖,以僅包含提供的矩形中的元素,但此實(shí)現(xiàn)依賴于緩存赞枕。因此澈缺,layoutAttributesForElementsInRect:方法只需要遍歷所有存儲(chǔ)的屬性,并將它們收集到一個(gè)返回給調(diào)用者的單個(gè)數(shù)組中炕婶。
清單6-7顯示了layoutAttributesForElementsInRect:方法的實(shí)現(xiàn)姐赡。代碼遍歷包含布局屬性對(duì)象的所有子字典,這些對(duì)象用于主字典_layoutInformation中特定類型的視圖柠掂。如果子字典中檢查的屬性包含在給定的矩形內(nèi)项滑,它們將被添加到存儲(chǔ)該矩形內(nèi)的所有屬性的數(shù)組中,該列在所有存儲(chǔ)的屬性都已被檢查之后返回涯贞。
清單6-7 收集和處理存儲(chǔ)的屬性

- (NSArray*)layoutAttributesForElementsInRect:(CGRect)rect {
    NSMutableArray *myAttributes [NSMutableArray arrayWithCapacity:self.layoutInformation.count];
    for(NSString *key in self.layoutInformation){
        NSDictionary *attributesDict = [self.layoutInformation objectForKey:key];
        for(NSIndexPath *key in attributesDict){
            UICollectionViewLayoutAttributes *attributes =
        [attributesDict objectForKey:key];
            if(CGRectIntersectsRect(rect, attributes.frame)){
                [attributes addObject:attributes];
            }
        }
    }
    return myAttributes;
}

注意:layoutAttributesForElementsInRect:的實(shí)現(xiàn)永遠(yuǎn)不會(huì)引用給定屬性的視圖是否可見(jiàn)枪狂。請(qǐng)記住,此方法提供的矩形不一定是可見(jiàn)矩形宋渔,無(wú)論您的實(shí)現(xiàn)是什么州疾,它都不應(yīng)該假定返回的屬性是可見(jiàn)的視圖。有關(guān)layoutAttributesForElementsInRect:方法的詳細(xì)討論傻谁,請(qǐng)參Providing Layout Attributes for Items in a Given Rectangle孝治。

當(dāng)請(qǐng)求時(shí)提供單獨(dú)的屬性

正如在需求中提供布局屬性的部分中所討論的那樣列粪,布局對(duì)象必須準(zhǔn)備好审磁,一旦布局過(guò)程完成,任何集合視圖中任何一個(gè)視圖的任意項(xiàng)都必須返回布局屬性岂座。對(duì)于所有三種視圖 - 單元格态蒂,補(bǔ)充視圖和裝飾視圖都有方法 - 但是應(yīng)用程序目前僅使用單元格,因此目前唯一需要實(shí)現(xiàn)的方法是layoutAttributesForItemAtIndexPath:方法费什。
清單6-8顯示了該方法的實(shí)現(xiàn)钾恢。它進(jìn)入單元格的存儲(chǔ)字典,在該子字典中鸳址,它返回以指定索引路徑存儲(chǔ)的屬性對(duì)象作為其鍵瘩蚪。
清單6-8提供特定items的屬性

- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath {
    return self.layoutInfo[@"MyCellKind"][indexPath];
}

圖6-4顯示了代碼中這一點(diǎn)的布局。所有的單元格已經(jīng)被正確地放置和調(diào)整以匹配他們的父視圖稿黍,但連接它們的線沒(méi)有被繪制疹瘦。

圖6-4
結(jié)合補(bǔ)充視圖

在當(dāng)前狀態(tài)下,應(yīng)用程序以分級(jí)方式正確顯示所有單元格巡球,但是由于沒(méi)有將父類與子項(xiàng)連接起來(lái)言沐,所以類圖難以解釋邓嘹。要繪制將類單元格連接到子項(xiàng)的線條,此應(yīng)用程序?qū)崿F(xiàn)依賴于可作為補(bǔ)充視圖并入布局的自定義視圖险胰。有關(guān)設(shè)計(jì)補(bǔ)充視圖的更多信息汹押,請(qǐng)參閱Elevating Content Through Supplementary Views
清單6-9顯示了可以并入到prepareLayout的實(shí)現(xiàn)中以包含補(bǔ)充視圖的代碼行起便。為單元格創(chuàng)建屬性對(duì)象和補(bǔ)充視圖之間的細(xì)微差別在于補(bǔ)充視圖的方法需要一個(gè)字符串標(biāo)識(shí)符才能告訴屬性對(duì)象的哪種補(bǔ)充視圖棚贾。這是因?yàn)樽远x布局可以有多種不同類型的補(bǔ)充視圖,而每個(gè)布局只能有一種類型的單元格榆综。
清單6-9為補(bǔ)充視圖創(chuàng)建屬性對(duì)象

// create another dictionary to specifically house the attributes for the supplementary view
NSMutableDictionary *supplementaryInfo = [NSMutableDictionary dictionary];
…
// within the initial pass over the data, create a set of attributes for the supplementary views as well
UICollectionViewLayoutAttributes *supplementaryAttributes = [UICollectionViewLayoutAttributes layoutAttributesForSupplementaryViewOfKind:@"ConnectionViewKind" withIndexPath:indexPath];
[supplementaryInfo setObject: supplementaryAttributes forKey:indexPath];
…
// in the second pass over the data, set the frame for the supplementary views just as you did for the cells
UICollectionViewLayoutAttributes *supplementaryAttributes = [supplementaryInfo objectForKey:indexPath];
supplementaryAttributes.frame = [self frameForSupplementaryViewOfKind:@"ConnectionViewKind" AtIndexPath:indexPath];
[supplementaryInfo setObject:supplementaryAttributes ForKey:indexPath];
...
// before setting the instance version of _layoutInformation, insert the local supplementaryInfo dictionary into the local layoutInformation dictionary
[layoutInformation setObject:supplementaryInfo forKey:@"ConnectionViewKind"];

因?yàn)檠a(bǔ)充視圖的代碼與單元格的代碼類似鸟悴,將此代碼并入prepareLayout方法很簡(jiǎn)單。該代碼對(duì)于補(bǔ)充視圖使用相同的緩存機(jī)制奖年,對(duì)于單元格细诸,使用專門用于ConnectionViewKind補(bǔ)充視圖的另一個(gè)字典。如果要添加多種補(bǔ)充視圖陋守,您將為該視圖創(chuàng)建另一個(gè)字典震贵,并為這種視圖添加這些代碼行。但在這種情況下水评,布局只需要一種補(bǔ)充視圖猩系。與初始化單元格布局屬性的代碼一樣,此實(shí)現(xiàn)使用自定義frameForSupplementaryViewOfKind:AtIndexPath:方法中燥,用于根據(jù)哪種視圖來(lái)確定補(bǔ)充視圖的frame寇甸。請(qǐng)記住,自定義adjustFramesOfChildrenAndConnectorsForClassAtIndexPath:在執(zhí)行prepareLayout方法時(shí)顯示疗涉,需要并入與類層次結(jié)構(gòu)布局相關(guān)的任何補(bǔ)充視圖的調(diào)整拿霉。
在示例代碼的情況下,在layoutAttributesForElementsInRect:實(shí)現(xiàn)中不需要修改任何內(nèi)容咱扣,因?yàn)樗辉O(shè)計(jì)為循環(huán)存儲(chǔ)在主字典中的所有屬性绽淘。只要將補(bǔ)充視圖屬性添加到主字典,所提供的layoutAttributesForElementsInRect的實(shí)現(xiàn)就如預(yù)期的那樣工作闹伪。
最后沪铭,與單元格一樣,集合視圖可以隨時(shí)請(qǐng)求特定視圖的補(bǔ)充視圖屬性偏瓤。因此杀怠,必須執(zhí)行layoutAttributesForSupplementaryElementOfKind:atIndexPath:的實(shí)現(xiàn)。
代碼清單6-10顯示了該方法的實(shí)現(xiàn)厅克,該方法與layoutAttributesForItemAtIndexPath:幾乎相同赔退。例外,使用提供的類型字符串而不是將類型的視圖硬編碼到返回值中已骇,可以在自定義布局中使用多個(gè)補(bǔ)充視圖离钝。
清單6-10根據(jù)需要提供補(bǔ)充視圖屬性

- (UICollectionViewLayoutAttributes *) layoutAttributesForSupplementaryViewOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath {
    return self.layoutInfo[kind][indexPath];
}
概括

通過(guò)包含補(bǔ)充視圖票编,您現(xiàn)在有一個(gè)可以充分重現(xiàn)類層次結(jié)構(gòu)圖的布局對(duì)象。在最后的實(shí)現(xiàn)中卵渴,您可能希望將調(diào)整納入自定義布局以節(jié)省空間慧域。本示例將探討自定義集合視圖布局的實(shí)際基礎(chǔ)實(shí)現(xiàn)。集合視圖非常強(qiáng)大浪读,并提供比這里更多的功能昔榴。移動(dòng),插入或刪除時(shí)突出顯示和選擇(甚至動(dòng)畫)單元格都是可以并入到應(yīng)用程序中的簡(jiǎn)單增強(qiáng)功能碘橘。要將您的自定義布局提升到一個(gè)新的水平券腔,請(qǐng)查看Creating Custom Layouts的最后幾個(gè)部分批钠。


官方文檔地址
Custom Layouts: A Worked Example

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子参滴,更是在濱河造成了極大的恐慌匈仗,老刑警劉巖算利,帶你破解...
    沈念sama閱讀 219,490評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件污筷,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡桥氏,警方通過(guò)查閱死者的電腦和手機(jī)温峭,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)字支,“玉大人凤藏,你說(shuō)我怎么就攤上這事《槲保” “怎么了揖庄?”我有些...
    開(kāi)封第一講書人閱讀 165,830評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)刃跛。 經(jīng)常有香客問(wèn)我抠艾,道長(zhǎng)苛萎,這世上最難降的妖魔是什么桨昙? 我笑而不...
    開(kāi)封第一講書人閱讀 58,957評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮腌歉,結(jié)果婚禮上蛙酪,老公的妹妹穿的比我還像新娘。我一直安慰自己翘盖,他們只是感情好桂塞,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,974評(píng)論 6 393
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著馍驯,像睡著了一般阁危。 火紅的嫁衣襯著肌膚如雪玛痊。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 51,754評(píng)論 1 307
  • 那天狂打,我揣著相機(jī)與錄音擂煞,去河邊找鬼。 笑死趴乡,一個(gè)胖子當(dāng)著我的面吹牛对省,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播晾捏,決...
    沈念sama閱讀 40,464評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼蒿涎,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了惦辛?” 一聲冷哼從身側(cè)響起劳秋,我...
    開(kāi)封第一講書人閱讀 39,357評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎胖齐,沒(méi)想到半個(gè)月后俗批,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,847評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡市怎,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,995評(píng)論 3 338
  • 正文 我和宋清朗相戀三年岁忘,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片区匠。...
    茶點(diǎn)故事閱讀 40,137評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡干像,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出驰弄,到底是詐尸還是另有隱情麻汰,我是刑警寧澤,帶...
    沈念sama閱讀 35,819評(píng)論 5 346
  • 正文 年R本政府宣布戚篙,位于F島的核電站五鲫,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏岔擂。R本人自食惡果不足惜位喂,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,482評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望乱灵。 院中可真熱鬧塑崖,春花似錦、人聲如沸痛倚。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 32,023評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至抒蚜,卻和暖如春掘鄙,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背嗡髓。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,149評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工通铲, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人器贩。 一個(gè)月前我還...
    沈念sama閱讀 48,409評(píng)論 3 373
  • 正文 我出身青樓颅夺,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親蛹稍。 傳聞我的和親對(duì)象是個(gè)殘疾皇子吧黄,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,086評(píng)論 2 355

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

  • 創(chuàng)建自定義布局 在開(kāi)始創(chuàng)建自定義布局之前,考慮清楚是否有這個(gè)必要唆姐。UICollectionViewFlowLayo...
    丨n水瓶座菜蟲灬閱讀 620評(píng)論 0 0
  • 翻譯自“Collection View Programming Guide for iOS” 0 關(guān)于iOS集合視...
    lakerszhy閱讀 3,869評(píng)論 1 22
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫(kù)拗慨、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,109評(píng)論 4 62
  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,185評(píng)論 25 707
  • // UnsafePointer// 對(duì)于底層 C API 進(jìn)行轉(zhuǎn)化的時(shí)候奉芦,Swift會(huì)轉(zhuǎn)換成 UnsafePoi...
    fordring2008閱讀 347評(píng)論 0 0