(修正)分享一個卡片式布局的collectionView

老規(guī)矩,先看效果圖

QQ20170817-152627.gif
第一步,自定義ZLFlowLayout繼承于UICollectionViewFlowLayout

具體代碼:

#import "ZLFlowLayout.h"
#import "ZLFlowLayoutConstants.h"

@implementation ZLFlowLayout


- (instancetype)init
{
    self = [super init];
    if (self)
    {
        self.minimumLineSpacing = 15.0f;
        self.itemSize = CGSizeMake(SCREEN_WIDTH - LEFT_OFFSET*2, (SCREEN_WIDTH - LEFT_OFFSET*2)/0.618f);
        self.scrollDirection = UICollectionViewScrollDirectionHorizontal;//設(shè)置為水平滑動
        self.sectionInset = UIEdgeInsetsMake(64, LEFT_OFFSET, 0, LEFT_OFFSET);
    }
    return self;
}

- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)oldBounds
{
    return YES;
}

- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
{
    NSArray * array = [[NSArray alloc]initWithArray:[super layoutAttributesForElementsInRect:rect] copyItems:YES];
    CGRect visiableRect;
    visiableRect.origin = self.collectionView.contentOffset;
    visiableRect.size = self.collectionView.bounds.size;

    for (UICollectionViewLayoutAttributes * attributes in array)
    {
        if (CGRectIntersectsRect(attributes.frame, rect))
        {
            CGFloat distance = CGRectGetMidX(visiableRect) - attributes.center.x;
            distance = ABS(distance);
            if (distance < SCREEN_WIDTH/2 + self.itemSize.width)
            {
                CGFloat zoom = 1 + ITEM_ZOOM * (1 - distance/THE_ACTIVE_DISTANCE);
                attributes.transform3D = CATransform3DMakeScale(zoom, zoom, 1.0f);
                attributes.transform3D = CATransform3DTranslate(attributes.transform3D, 0, -zoom * 25, 0);
                attributes.alpha = zoom - ITEM_ZOOM;
            }
        }
    }
    return array;
}

- (CGPoint )targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity
{
    CGFloat offsetAdjustment = MAXFLOAT;
    CGFloat horizontalCenter_X = proposedContentOffset.x + CGRectGetWidth(self.collectionView.bounds)/2.0;
    CGRect targetRect = CGRectMake(proposedContentOffset.x, 0, self.collectionView.bounds.size.width, self.collectionView.bounds.size.height);
    NSArray *array = [super layoutAttributesForElementsInRect:targetRect];
    for (UICollectionViewLayoutAttributes * attributes in array)
    {
        CGFloat itemHorizontalCenter_X = attributes.center.x;
        if (ABS(itemHorizontalCenter_X - horizontalCenter_X) < ABS(offsetAdjustment))
        {
            offsetAdjustment = itemHorizontalCenter_X - horizontalCenter_X;
        }
    }
    return CGPointMake(proposedContentOffset.x + offsetAdjustment, proposedContentOffset.y);
}
第二步,創(chuàng)建collectionView
#import "ZLCollectionView.h"
#import "ZLFlowLayout.h"

static NSString * identifier = @"collecitonView_cell";
@interface ZLCollectionView ()<UICollectionViewDelegate,UICollectionViewDataSource>

@property (nonatomic,strong) UICollectionView *mainCollectionView;
@property (nonatomic,assign) NSInteger itemCount;
@property (nonatomic,assign) CGRect collectionViewFrame;

@end

@implementation ZLCollectionView


+ (instancetype)collectionViewWithFrame:(CGRect)frame itemCount:(NSInteger)itemCount
{
    return [[self alloc]initWithFrame:frame itemCount:itemCount];
}

- (instancetype)initWithFrame:(CGRect)frame itemCount:(NSInteger)itemCount
{
    self = [super initWithFrame:frame];
    if (self)
    {
        self.itemCount = itemCount;
        self.collectionViewFrame = frame;
        [self createCollectionViewStyle];
    }
    return self;
}


- (void)createCollectionViewStyle
{
    ZLFlowLayout *layout = [[ZLFlowLayout alloc]init];
    self.mainCollectionView = [[UICollectionView alloc]initWithFrame:self.collectionViewFrame collectionViewLayout:layout];
    self.mainCollectionView.delegate = self;
    self.mainCollectionView.dataSource = self;
    self.mainCollectionView.backgroundColor = [UIColor groupTableViewBackgroundColor];
    self.mainCollectionView.showsHorizontalScrollIndicator = NO;
    [self addSubview:self.mainCollectionView];

    NSLog(@"%f -- %f",layout.itemSize.width,layout.itemSize.height); //375.404


    //注冊cell
    [self.mainCollectionView registerClass:[UICollectionViewCell class]
                forCellWithReuseIdentifier:identifier];
}

- (NSInteger )numberOfItemsInSection:(NSInteger)section
{
    return 1;
}
- (NSInteger )collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
    return self.itemCount;
}
- (__kindof CustomCollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
    CustomCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:identifier
                                                                           forIndexPath:indexPath];

    /*這段代碼的作用就是:
     *當直接往細胞上面添加視圖內(nèi)容時,隨著滑動,可能會出現(xiàn)內(nèi)容重疊的問題。
     *但是在自定義細胞時使用這段代碼,就會移除細胞的所有子視圖,
     *使用Masonry給電池子視圖上的內(nèi)容進行約束就會崩潰,或者直接給細胞上的內(nèi)容進行約束時就會出現(xiàn)細胞顯示而上面內(nèi)容不顯示的問題。
    //這一步,防止cell上面的內(nèi)容發(fā)生重疊
    for (UIView * view in cell.subviews)
    {
        [view removeFromSuperview];
    }
     */

    cell.backgroundColor = [UIColor lightGrayColor];
    cell.layer.masksToBounds = YES;
    cell.layer.cornerRadius = 5.0f;

    
    NSLog(@"Cell:%f--%f",cell.frame.size.width,cell.frame.size.height);
    return cell;
}

- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
    self.selectedItems(indexPath);
}

- (void)didSelectedItemsWithBlock:(DidSelectedItems)selectedItems
{
    self.selectedItems = selectedItems;
}
@end
第三步、使用
ZLCollectionView *collectionView = [ZLCollectionView collectionViewWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height) itemCount:30];
[collectionView didSelectedItemsWithBlock:^(NSIndexPath *indexPath) {
   NSLog(@"ItemTag:%ld",indexPath.item);
}];
[self.view addSubview:collectionView];

說明

可以通過修改ZLFlowLayoutConstants.hITEM_ZOOMTHE_ACTIVE_DISTANCELEFT_OFFSET的值,來修改卡片item的大小樣式

之前會一直遇到這個警告提示

2017-08-17 16:18:17.133324+0800 ZLCollectionViewFlowLayout[4342:480201] Logging only once for UICollectionViewFlowLayout cache mismatched frame
2017-08-17 16:18:17.133680+0800 ZLCollectionViewFlowLayout[4342:480201] UICollectionViewFlowLayout has cached frame mismatch for index path <NSIndexPath: 0xc000000000000016> {length = 2, path = 0 - 0} - cached value: {{55, 86.346884732472063}, {210, 339.80584123617336}}; expected value: {{60, 122}, {200, 323.62461070111749}}
2017-08-17 16:18:17.133859+0800 ZLCollectionViewFlowLayout[4342:480201] This is likely occurring because the flow layout subclass ZLFlowLayout is modifying attributes returned by UICollectionViewFlowLayout without copying them

后來百度了一下,將layoutAttributesForElementsInRect中的NSArray * array = [super layoutAttributesForElementsInRect:rect];換成NSArray * array = [[NSArray alloc]initWithArray:[super layoutAttributesForElementsInRect:rect] copyItems:YES];就解決了。

這是我的github地址,有喜歡的可以star一下,謝謝了。

=======================================================================================================

更正

2017-11-24
=======================================================================================================

之前有小伙伴私信問起使用Masonry自定義cell,會出現(xiàn)-崩潰-或者-內(nèi)容顯示不出來但cell能顯示-的問題,把ZLCollectionView.m中的下面一段代碼注釋了就行。

//這一步,防止cell上面的內(nèi)容發(fā)生重疊
    for (UIView * view in cell.subviews)
    {
        [view removeFromSuperview];
    }

這段代碼的作用就是:

當直接往cell上面添加視圖內(nèi)容時,隨著滑動,可能會出現(xiàn)內(nèi)容重疊的問題。但是在自定義cell時使用這段代碼,就會移除cell的所有子視圖,使用Masonry給cell子視圖上的內(nèi)容進行約束就會崩潰,或者直接給cell上的內(nèi)容進行約束時就會出現(xiàn)cell顯示而上面內(nèi)容不顯示的問題。

我修改一下demo,標注了這個問題,添加了自定義cell的內(nèi)容,有需要的小伙伴可以去我github下載一下。

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

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