初探UICollectionViewCompositionalLayout

因?yàn)閁ICollectionViewCompositionalLayout,再次愛上UICollectionView。

最近在做橫向滾動(dòng)的UICollectionView的時(shí)候,cell不是全屏的,又想實(shí)現(xiàn)按cell分頁(yè)效果而不是按屏幕寬度分頁(yè),我注意到AppStore的游戲和App tab頁(yè)面橫向滾動(dòng)的效果非常棒,在搜索過程中發(fā)現(xiàn)了UICollectionViewCompositionalLayout關(guān)鍵字,遂把玩之。(UICollectionViewCompositionalLayout在WWDC2019就推出的,然而我并沒有看WWDC,也不是第一時(shí)間更新到最新系統(tǒng)去吃螃蟹者,寫到這里其實(shí)內(nèi)心有點(diǎn)慚愧??)

至于怎么在iOS13以下實(shí)現(xiàn)按cell分頁(yè)效果的,感興趣的可以看上篇:Paging UICollectionView by smaller cells, not screen

UICollectionViewCompositionalLayout是蘋果在iOS13推出的一個(gè)高度自適應(yīng)和靈活的布局對(duì)象,它是UICollectionView的一種布局方式,它的設(shè)計(jì)是可組合的、靈活的和快速的。

我們先看下iOS13上AppStore上的頁(yè)面效果,嵌套交叉滾動(dòng),算是正常的需求了,如果要我們做,我們肯定是用類似cell上嵌套UICollectionView的思路來實(shí)現(xiàn),我們不僅要寫縱向的cell樣式、橫向的cell樣式,還要處理嵌套cell的點(diǎn)擊事件,簡(jiǎn)直是太繁瑣了。

AppStore

現(xiàn)在,有了UICollectionViewCompositionalLayout這把金剛鉆,整個(gè)頁(yè)面我們使用一個(gè)UICollectionView即可實(shí)現(xiàn),在我們配置好UICollectionViewCompositionalLayout布局樣式后,剩下的,放眼望去,滿屏皆是這一個(gè)UICollectionView的cell,是不是很簡(jiǎn)單?(蘋果公司終于考慮到了這一點(diǎn),然而啥時(shí)候才能最低支持iOS13?)

下面來結(jié)合demo一起解開UICollectionViewCompositionalLayout的神秘面紗。

主要概念

UICollectionViewCompositionalLayout.png

由圖可見,層級(jí)關(guān)系為 NSCollectionLayoutItem -> NSCollectionLayoutGroup -> NSCollectionLayoutSection

其中:

  • NSCollectionLayoutDimension 維度尺寸
    用來創(chuàng)建NSCollectionLayoutSize,有按占group的比例創(chuàng)建尺寸fractionalWidthDimension:、fractionalHeightDimension:,按固定值創(chuàng)建尺寸absoluteDimension:、按預(yù)估值創(chuàng)建尺寸estimatedDimension:的方法。

  • NSCollectionLayoutSize 布局尺寸
    NSCollectionLayoutItem和NSCollectionLayoutGroup在初始化時(shí)都需要通過其指定尺寸

  • NSCollectionLayoutItem 布局單元
    可以配置尺寸、裝飾視圖

  • NSCollectionLayoutGroup 分組
    是NSCollectionLayoutItem的子類,支持橫向、縱向、自定義分組。注意interItemSpacing屬性只對(duì)NSCollectionLayoutGroup創(chuàng)建時(shí)指定了多個(gè)item的才有效。

  • NSCollectionLayoutSection 分區(qū)
    與group綁定,可以通過boundarySupplementaryItems制定組頭組尾、通過visibleItemsInvalidationHandler監(jiān)聽滾動(dòng),通過orthogonalScrollingBehavior設(shè)置在交叉軸上如何滾動(dòng)與分頁(yè)。

  • UICollectionViewCompositionalLayout 組合布局
    與NSCollectionLayoutSection綁定,initWithSectionProvider方可以滿足為UICollectionView的每個(gè)Section配置不同的NSCollectionLayoutSection。

NSCollectionLayoutItem的對(duì)齊方式

edgespacing

首先,這里創(chuàng)建了一個(gè)group,包含一大一小不同的item,我們想讓小的item水平垂直居中,主要用到了item的edgeSpacing屬性,這里使用NSCollectionLayoutSpacing創(chuàng)建了一個(gè)距離邊界都保持相同的靈活間距。這里注意一點(diǎn),這里創(chuàng)建group時(shí)指定了多個(gè)item,所以設(shè)置interItemSpacing屬性才有效果,如果只指定了一個(gè)item,該屬性不起效。

//大item 寬占group的一半,高占滿group
NSCollectionLayoutSize *itemSize = [NSCollectionLayoutSize sizeWithWidthDimension:[NSCollectionLayoutDimension fractionalWidthDimension:0.5] heightDimension:[NSCollectionLayoutDimension fractionalHeightDimension:1.0]];
NSCollectionLayoutItem *item = [NSCollectionLayoutItem itemWithLayoutSize:itemSize];

//小item 寬占group的四分之一,高占group的一半
NSCollectionLayoutSize *itemSize1 = [NSCollectionLayoutSize sizeWithWidthDimension:[NSCollectionLayoutDimension fractionalWidthDimension:0.25] heightDimension:[NSCollectionLayoutDimension fractionalHeightDimension:0.5]];
NSCollectionLayoutItem *item1 = [NSCollectionLayoutItem itemWithLayoutSize:itemSize1];
item1.contentInsets = NSDirectionalEdgeInsetsMake(20, 20, 20, 20);//內(nèi)邊距 會(huì)改變其size
//item1.edgeSpacing = [NSCollectionLayoutEdgeSpacing spacingForLeading:nil top:[NSCollectionLayoutSpacing flexibleSpacing:10] trailing:nil bottom:nil];//外邊距,值可能會(huì)被優(yōu)化 【相對(duì)于group底部對(duì)齊】
item1.edgeSpacing = [NSCollectionLayoutEdgeSpacing spacingForLeading:[NSCollectionLayoutSpacing flexibleSpacing:10] top:[NSCollectionLayoutSpacing flexibleSpacing:10] trailing:[NSCollectionLayoutSpacing flexibleSpacing:10] bottom:[NSCollectionLayoutSpacing flexibleSpacing:10]];//【相對(duì)于group居中對(duì)齊】

//一個(gè)group可以指定多個(gè)item,指定多個(gè),對(duì)應(yīng)的cell會(huì)按items的樣式依次布局
NSCollectionLayoutSize *groupSize = [NSCollectionLayoutSize sizeWithWidthDimension:[NSCollectionLayoutDimension fractionalWidthDimension:1.0] heightDimension:[NSCollectionLayoutDimension fractionalWidthDimension:0.25]];
NSCollectionLayoutGroup *group = [NSCollectionLayoutGroup horizontalGroupWithLayoutSize:groupSize subitems:@[item, item1]];
//interItemSpacing對(duì)指定了多個(gè)subitems才有效
group.interItemSpacing = [NSCollectionLayoutSpacing fixedSpacing:5];

//一個(gè)section只能指定一個(gè)group
NSCollectionLayoutSection *section = [NSCollectionLayoutSection sectionWithGroup:group];
section.contentInsets = NSDirectionalEdgeInsetsFromString(@"{5.0, 5.0, 5.0, 5.0}");
    
//layout只能指定一個(gè)section
UICollectionViewCompositionalLayout *layout = [[UICollectionViewCompositionalLayout alloc]initWithSection:section configuration:config];

組合group、組頭組尾、補(bǔ)充視圖

組合group&組頭組尾&badge

由于NSCollectionLayoutGroup繼承自NSCollectionLayoutItem,在創(chuàng)建NSCollectionLayoutGroup時(shí)需要指定NSCollectionLayoutItem,所以,我們就可以把group和item進(jìn)行組合來組合出一個(gè)新的group。

可以通過下面的方式創(chuàng)建組頭組尾以及補(bǔ)充視圖:

//配置裝飾Badge
//裝飾視圖中心點(diǎn)等于cell的右上角頂點(diǎn)
NSCollectionLayoutAnchor *badgeAnchor = [NSCollectionLayoutAnchor layoutAnchorWithEdges:NSDirectionalRectEdgeTop|NSDirectionalRectEdgeTrailing fractionalOffset:CGPointMake(0.5, -0.5)];
NSCollectionLayoutSize *badgeSize = [NSCollectionLayoutSize sizeWithWidthDimension:[NSCollectionLayoutDimension absoluteDimension:20] heightDimension:[NSCollectionLayoutDimension absoluteDimension:20]];
NSCollectionLayoutSupplementaryItem *badge = [NSCollectionLayoutSupplementaryItem supplementaryItemWithLayoutSize:badgeSize elementKind:@"Badge" containerAnchor:badgeAnchor];

//頂部大item
NSCollectionLayoutSize *topItemSize = [NSCollectionLayoutSize sizeWithWidthDimension:[NSCollectionLayoutDimension fractionalWidthDimension:1.0] heightDimension:[NSCollectionLayoutDimension fractionalWidthDimension:9.0/16.0]];
NSCollectionLayoutItem *topItem = [NSCollectionLayoutItem itemWithLayoutSize:topItemSize];

//底部小item 通過supplementaryItems屬性指定裝飾badge視圖
NSCollectionLayoutSize *bottomItemSize = [NSCollectionLayoutSize sizeWithWidthDimension:[NSCollectionLayoutDimension fractionalWidthDimension:0.5] heightDimension:[NSCollectionLayoutDimension fractionalHeightDimension:1.0]];
NSCollectionLayoutItem *bottomItem = [NSCollectionLayoutItem itemWithLayoutSize:bottomItemSize supplementaryItems:@[badge]];
bottomItem.contentInsets = NSDirectionalEdgeInsetsMake(8, 8, 8, 8);

//底部放兩個(gè)小item對(duì)應(yīng)的group
NSCollectionLayoutSize *bottomGroupSize = [NSCollectionLayoutSize sizeWithWidthDimension:[NSCollectionLayoutDimension fractionalWidthDimension:1.0] heightDimension:[NSCollectionLayoutDimension fractionalWidthDimension:0.5]];
//注意:該api放兩個(gè)相同的item是不起效的
//NSCollectionLayoutGroup *bottomGroup = [NSCollectionLayoutGroup horizontalGroupWithLayoutSize:bottomGroupSize subitems:@[bottomItem, bottomItem]];
////會(huì)在這個(gè)分組中放入兩個(gè)相同的item。并且這里設(shè)置了2,即使bottomItemSize width設(shè)置比較大,依然會(huì)平分
NSCollectionLayoutGroup *bottomGroup = [NSCollectionLayoutGroup horizontalGroupWithLayoutSize:bottomGroupSize subitem:bottomItem count:2];

//組合group ???? 注意這里的尺寸一點(diǎn)要是組合的大小
NSCollectionLayoutSize *fullGroupSize = [NSCollectionLayoutSize sizeWithWidthDimension:[NSCollectionLayoutDimension fractionalWidthDimension:1.0] heightDimension:[NSCollectionLayoutDimension fractionalWidthDimension:9.0/16.0 + 0.5]];
NSCollectionLayoutGroup *nestedGroup = [NSCollectionLayoutGroup verticalGroupWithLayoutSize:fullGroupSize subitems:@[topItem, bottomGroup]];

//雖然一個(gè)section只能指定一個(gè)group,但可以group中可以組合item和其他group
NSCollectionLayoutSection *section = [NSCollectionLayoutSection sectionWithGroup:nestedGroup];
    
NSCollectionLayoutSize *headerSize = [NSCollectionLayoutSize sizeWithWidthDimension:[NSCollectionLayoutDimension fractionalWidthDimension:1.0] heightDimension:[NSCollectionLayoutDimension estimatedDimension:44]];
NSCollectionLayoutBoundarySupplementaryItem *headerItem = [NSCollectionLayoutBoundarySupplementaryItem boundarySupplementaryItemWithLayoutSize:headerSize elementKind:UICollectionElementKindSectionHeader alignment:NSRectAlignmentTop];
//是否懸停
//headerItem.pinToVisibleBounds = YES;
    
//配置組頭組尾
NSCollectionLayoutSize *footerSize = [NSCollectionLayoutSize sizeWithWidthDimension:[NSCollectionLayoutDimension fractionalWidthDimension:1.0] heightDimension:[NSCollectionLayoutDimension estimatedDimension:60]];
NSCollectionLayoutBoundarySupplementaryItem *footerItem = [NSCollectionLayoutBoundarySupplementaryItem boundarySupplementaryItemWithLayoutSize:footerSize elementKind:UICollectionElementKindSectionFooter alignment:NSRectAlignmentBottom];

//給section的boundarySupplementaryItems屬性賦值
section.boundarySupplementaryItems = @[headerItem, footerItem];

通過這個(gè)demo,我們還可以看出UICollectionView的numberOfSections和NSCollectionLayoutSection的關(guān)系。這里我第一個(gè)分區(qū)的numberOfSections=2,numberOfRows=8,每個(gè)NSCollectionLayoutSection可以放下三個(gè)cell,實(shí)際效果是會(huì)按這個(gè)NSCollectionLayoutSection樣式依次布局cell,但每個(gè)numberOfSections對(duì)應(yīng)的分區(qū)開始的時(shí)候一定是從一個(gè)新的NSCollectionLayoutSection布局開始的,我們看下兩個(gè)分區(qū)的交界處即可理解:

分區(qū)交界處

用裝飾視圖做背景,實(shí)現(xiàn)類似UITableViewStyleGrouped樣式

類似UITableViewStyleGrouped樣式

//group加裝飾背景
1.創(chuàng)建NSCollectionLayoutDecorationItem 它是NSCollectionLayoutItem的子類,不能指定layoutSize。
2.給NSCollectionLayoutSection的decorationItems賦值。
3.在UICollectionViewCompositionalLayout上面注冊(cè)decorationView,在這里注冊(cè)的類實(shí)現(xiàn)樣式的自定義。
注意:不是在collectionview上注冊(cè)SupplementaryView。

NSCollectionLayoutSize *itemSize = [NSCollectionLayoutSize sizeWithWidthDimension:[NSCollectionLayoutDimension fractionalWidthDimension:1.0] heightDimension:[NSCollectionLayoutDimension fractionalHeightDimension:1.0]];
NSCollectionLayoutItem *item = [NSCollectionLayoutItem itemWithLayoutSize:itemSize];

NSCollectionLayoutSize *groupSize = [NSCollectionLayoutSize sizeWithWidthDimension:[NSCollectionLayoutDimension fractionalWidthDimension:1.0] heightDimension:[NSCollectionLayoutDimension absoluteDimension:44]];
NSCollectionLayoutGroup *group = [NSCollectionLayoutGroup verticalGroupWithLayoutSize:groupSize subitems:@[item]];

NSCollectionLayoutSection *section = [NSCollectionLayoutSection sectionWithGroup:group];
section.contentInsets = NSDirectionalEdgeInsetsMake(20, 20, 20, 20);

NSCollectionLayoutDecorationItem *backItem = [NSCollectionLayoutDecorationItem backgroundDecorationItemWithElementKind:@"background"];
backItem.contentInsets = NSDirectionalEdgeInsetsMake(10, 10, 10, 10);
section.decorationItems = @[backItem];

UICollectionViewCompositionalLayoutConfiguration *config = [UICollectionViewCompositionalLayoutConfiguration new];
config.interSectionSpacing = 20;//不同section之間的間距

UICollectionViewCompositionalLayout *layout = [[UICollectionViewCompositionalLayout alloc]initWithSection:section configuration:config];
[layout registerClass:[MyDecorateView class] forDecorationViewOfKind:@"background"];

自定義NSCollectionLayoutGroup

上面的demo都是水平或垂直的group樣式,系統(tǒng)也提供了自定義group樣式的api,這里只是簡(jiǎn)單舉個(gè)例子。

自定義NSCollectionLayoutGroup
NSCollectionLayoutSize *groupSize = [NSCollectionLayoutSize sizeWithWidthDimension:[NSCollectionLayoutDimension fractionalWidthDimension:1.0] heightDimension:[NSCollectionLayoutDimension absoluteDimension:200]];

CGFloat width = [UIScreen mainScreen].bounds.size.width/3.0;
CGFloat height = 200/3.0;
//無法橫向滾動(dòng)
NSCollectionLayoutGroup *group = [NSCollectionLayoutGroup customGroupWithLayoutSize:groupSize itemProvider:^NSArray<NSCollectionLayoutGroupCustomItem *> * _Nonnull(id<NSCollectionLayoutEnvironment>  _Nonnull layoutEnvironment) {
    //UICollectionView的每個(gè)section走一次
    //這里想象空間很大,自己愛咋放咋放
    NSMutableArray *arr = [NSMutableArray arrayWithCapacity:8];
    CGFloat x = 0 , y = 0;
    for(NSInteger i = 0; i < 8; i++){
        NSCollectionLayoutGroupCustomItem *customItem = [NSCollectionLayoutGroupCustomItem customItemWithFrame:CGRectMake(x, y, width, height) zIndex:1000+i];
        [arr addObject:customItem];
        x += width;
        if(i > 0 && i % 3 == 0){
            x = 0;
            y += height;
        }
    }
    return arr.copy;
}];

綜合實(shí)現(xiàn)類似AppStore tab頁(yè)的效果

結(jié)合上面的例子,同時(shí)再實(shí)現(xiàn)為UICollectionView的每個(gè)分區(qū)都單獨(dú)配置一個(gè)不同的section樣式來實(shí)現(xiàn)目標(biāo)效果。

AppStore布局效果

其中知識(shí)點(diǎn):

  • 如何監(jiān)測(cè)橫向滾動(dòng)的group當(dāng)前滾動(dòng)到了哪個(gè)cell?
    section的visibleItemsInvalidationHandler屬性

  • 正交軸上滾動(dòng)模式
    UICollectionLayoutSectionOrthogonalScrollingBehaviorContinuous 正常連續(xù)滾動(dòng)
    UICollectionLayoutSectionOrthogonalScrollingBehaviorPaging 正常分頁(yè)輪播(頁(yè)寬等于UICollectionView的寬度)
    UICollectionLayoutSectionOrthogonalScrollingBehaviorContinuousGroupLeadingBoundary 停止?jié)L動(dòng)時(shí)一定會(huì)停留在group的邊界處
    UICollectionLayoutSectionOrthogonalScrollingBehaviorGroupPaging 按group的尺寸進(jìn)行分頁(yè)
    UICollectionLayoutSectionOrthogonalScrollingBehaviorGroupPagingCentered 也是按group的尺寸進(jìn)行分頁(yè),但會(huì)沿正交軸增加首尾間距讓group居中

UICollectionViewCompositionalLayoutConfiguration *config = [UICollectionViewCompositionalLayoutConfiguration new];
config.interSectionSpacing = 30;//不同section之間的間距
    
    
UICollectionViewCompositionalLayout *layout = [[UICollectionViewCompositionalLayout alloc]initWithSectionProvider:^NSCollectionLayoutSection * _Nullable(NSInteger section, id<NSCollectionLayoutEnvironment> environment) {
     return [self generateSectionForSection:section];
}];
layout.configuration = config;


- (NSCollectionLayoutSection *)generateSectionForSection:(NSInteger)section
{
    NSCollectionLayoutGroup *group;
    NSDirectionalEdgeInsets sectionInsets = NSDirectionalEdgeInsetsMake(0, 0, 0, 0);
    UICollectionLayoutSectionOrthogonalScrollingBehavior behavior = UICollectionLayoutSectionOrthogonalScrollingBehaviorContinuous;
    switch (section) {
        case 0:
        case 5:
        {
            //頂部banner item
            //效果:paging by cell 看起來cell距離屏幕左右各20像素
            sectionInsets = NSDirectionalEdgeInsetsMake(0, 15, 0, 15);
            behavior = UICollectionLayoutSectionOrthogonalScrollingBehaviorGroupPaging;//完美的paging by cell效果
            
            CGFloat bannerSize = [UIScreen mainScreen].bounds.size.width - 30;//原本占screenwidth-30
            NSCollectionLayoutSize *bannerItemSize = [NSCollectionLayoutSize sizeWithWidthDimension:[NSCollectionLayoutDimension fractionalWidthDimension:1.0] heightDimension:[NSCollectionLayoutDimension fractionalHeightDimension:1.0]];
            NSCollectionLayoutItem *bannerItem = [NSCollectionLayoutItem itemWithLayoutSize:bannerItemSize];
            bannerItem.contentInsets = NSDirectionalEdgeInsetsMake(0, 5, 0, 5);//左右各收縮5像素 占screenwidth-40

            NSCollectionLayoutSize *bannerGroupSize = [NSCollectionLayoutSize sizeWithWidthDimension:[NSCollectionLayoutDimension absoluteDimension:bannerSize] heightDimension:[NSCollectionLayoutDimension absoluteDimension:bannerSize]];
            group = [NSCollectionLayoutGroup horizontalGroupWithLayoutSize:bannerGroupSize subitem:bannerItem count:1];//水平
            break;
        }
        case 1:
        case 2:
        case 4:
        case 7:
        case 9:
        case 10:
        {
            //每列三行的cell樣式
            sectionInsets = NSDirectionalEdgeInsetsMake(0, 15, 0, 15);
            behavior = UICollectionLayoutSectionOrthogonalScrollingBehaviorGroupPaging;//完美的paging by cell效果

            CGFloat oneThirdWidth = [UIScreen mainScreen].bounds.size.width - 30;
            CGFloat oneThirdHeight = 80;
            NSCollectionLayoutSize *oneThirdItemSize = [NSCollectionLayoutSize sizeWithWidthDimension:[NSCollectionLayoutDimension fractionalWidthDimension:1.0] heightDimension:[NSCollectionLayoutDimension fractionalHeightDimension:1.0/3.0]];
            NSCollectionLayoutItem *oneThirdItem = [NSCollectionLayoutItem itemWithLayoutSize:oneThirdItemSize];
            oneThirdItem.contentInsets = NSDirectionalEdgeInsetsMake(0, 5, 0, 5);

            NSCollectionLayoutSize *oneThirdGroupSize = [NSCollectionLayoutSize sizeWithWidthDimension:[NSCollectionLayoutDimension absoluteDimension:oneThirdWidth] heightDimension:[NSCollectionLayoutDimension absoluteDimension:oneThirdHeight * 3.0]];
            group = [NSCollectionLayoutGroup verticalGroupWithLayoutSize:oneThirdGroupSize subitem:oneThirdItem count:3];//垂直
            
            break;
        }
        case 3:
        {
            //今天看什么banner
            sectionInsets = NSDirectionalEdgeInsetsMake(0, 15, 0, 15);
            behavior = UICollectionLayoutSectionOrthogonalScrollingBehaviorGroupPaging;//完美的paging by cell效果

            CGFloat bannerWidth = [UIScreen mainScreen].bounds.size.width - 150;
            CGFloat bannerHeight = 180;
            NSCollectionLayoutSize *bannerItemSize = [NSCollectionLayoutSize sizeWithWidthDimension:[NSCollectionLayoutDimension fractionalWidthDimension:1.0] heightDimension:[NSCollectionLayoutDimension fractionalHeightDimension:1.0]];
            NSCollectionLayoutItem *bannerItem = [NSCollectionLayoutItem itemWithLayoutSize:bannerItemSize];
            bannerItem.contentInsets = NSDirectionalEdgeInsetsMake(0, 5, 0, 5);

            NSCollectionLayoutSize *bannerGroupSize = [NSCollectionLayoutSize sizeWithWidthDimension:[NSCollectionLayoutDimension absoluteDimension:bannerWidth] heightDimension:[NSCollectionLayoutDimension absoluteDimension:bannerHeight]];
            group = [NSCollectionLayoutGroup horizontalGroupWithLayoutSize:bannerGroupSize subitem:bannerItem count:1];//水平
            
            break;
        }
        case 6:
        {
            //熱門類別
            sectionInsets = NSDirectionalEdgeInsetsMake(0, 20, 0, 20);

            CGFloat cellWidth = [UIScreen mainScreen].bounds.size.width - 40;
            CGFloat cellHeight = 50;
            NSCollectionLayoutSize *itemSize = [NSCollectionLayoutSize sizeWithWidthDimension:[NSCollectionLayoutDimension fractionalWidthDimension:1.0] heightDimension:[NSCollectionLayoutDimension fractionalHeightDimension:1.0]];
            NSCollectionLayoutItem *item = [NSCollectionLayoutItem itemWithLayoutSize:itemSize];

            NSCollectionLayoutSize *groupSize = [NSCollectionLayoutSize sizeWithWidthDimension:[NSCollectionLayoutDimension absoluteDimension:cellWidth] heightDimension:[NSCollectionLayoutDimension absoluteDimension:cellHeight * 8]];
            group = [NSCollectionLayoutGroup verticalGroupWithLayoutSize:groupSize subitem:item count:8];//垂直
            break;
        }
        case 8:
        {
            //每列兩行的cell樣式
            sectionInsets = NSDirectionalEdgeInsetsMake(0, 15, 0, 15);
            behavior = UICollectionLayoutSectionOrthogonalScrollingBehaviorGroupPaging;//完美的paging by cell效果
            
            CGFloat oneSecondWidth = [UIScreen mainScreen].bounds.size.width - 30;
            CGFloat oneSecondHeight = 120;
            NSCollectionLayoutSize *oneSecondItemSize = [NSCollectionLayoutSize sizeWithWidthDimension:[NSCollectionLayoutDimension fractionalWidthDimension:1.0] heightDimension:[NSCollectionLayoutDimension fractionalHeightDimension:1.0/2.0]];
            NSCollectionLayoutItem *oneSecondItem = [NSCollectionLayoutItem itemWithLayoutSize:oneSecondItemSize];
            oneSecondItem.contentInsets = NSDirectionalEdgeInsetsMake(0, 5, 0, 5);

            NSCollectionLayoutSize *oneSecondGroupSize = [NSCollectionLayoutSize sizeWithWidthDimension:[NSCollectionLayoutDimension absoluteDimension:oneSecondWidth] heightDimension:[NSCollectionLayoutDimension absoluteDimension:oneSecondHeight * 2.0]];
            group = [NSCollectionLayoutGroup verticalGroupWithLayoutSize:oneSecondGroupSize subitem:oneSecondItem count:2];//垂直
            break;
        }
        case 11:
        {
            //快速鏈接
            sectionInsets = NSDirectionalEdgeInsetsMake(0, 20, 0, 20);

            CGFloat cellWidth = [UIScreen mainScreen].bounds.size.width - 40;
            CGFloat cellHeight = 50;
            NSCollectionLayoutSize *itemSize = [NSCollectionLayoutSize sizeWithWidthDimension:[NSCollectionLayoutDimension fractionalWidthDimension:1.0] heightDimension:[NSCollectionLayoutDimension fractionalHeightDimension:1.0]];
            NSCollectionLayoutItem *item = [NSCollectionLayoutItem itemWithLayoutSize:itemSize];

            NSCollectionLayoutSize *groupSize = [NSCollectionLayoutSize sizeWithWidthDimension:[NSCollectionLayoutDimension absoluteDimension:cellWidth] heightDimension:[NSCollectionLayoutDimension absoluteDimension:cellHeight * 8]];
            group = [NSCollectionLayoutGroup verticalGroupWithLayoutSize:groupSize subitem:item count:8];//垂直
            break;
            break;
        }
    }
    
    NSCollectionLayoutSection *layoutSection = [NSCollectionLayoutSection sectionWithGroup:group];
    layoutSection.orthogonalScrollingBehavior = behavior;
    layoutSection.contentInsets = sectionInsets;
    if(section == 0){
        layoutSection.visibleItemsInvalidationHandler = ^(NSArray<id<NSCollectionLayoutVisibleItem>> * _Nonnull visibleItems, CGPoint contentOffset, id<NSCollectionLayoutEnvironment>  _Nonnull layoutEnvironment) {
            //這里可以判斷哪個(gè)cell滾動(dòng)到了屏幕中心
        };
    }
    
    //配置組頭組尾
    NSCollectionLayoutSize *headerSize = [NSCollectionLayoutSize sizeWithWidthDimension:[NSCollectionLayoutDimension fractionalWidthDimension:1.0] heightDimension:[NSCollectionLayoutDimension estimatedDimension:44]];
    NSCollectionLayoutBoundarySupplementaryItem *headerItem = [NSCollectionLayoutBoundarySupplementaryItem boundarySupplementaryItemWithLayoutSize:headerSize elementKind:UICollectionElementKindSectionHeader alignment:NSRectAlignmentTop];
    
    layoutSection.boundarySupplementaryItems = @[headerItem];
    
    return layoutSection;
}

總結(jié)

UICollectionViewCompositionalLayout是繼UICollectionViewFlowLayout之后,蘋果公司為開發(fā)者提供的一個(gè)更加靈活功能更加強(qiáng)大的一種布局方案。這是順應(yīng)時(shí)代的產(chǎn)物,是iOS開發(fā)者的開發(fā)利器,可以很大程度上提升開發(fā)效率,用更少的時(shí)間完成更復(fù)雜的布局效果。??除了API越來與長(zhǎng)外,其他沒什么毛病??。

源碼已放至Github: ATPagingByCell

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容