UICollectionView自定义布局(石工布局)

UICollectionView自定义布局(石工布局)


效果:

MKMasonryViewLayout调用顺序


  1. numberOfSectionsInCollectionView(dataSource)
    • (计算section个数)
  • numberOfItemsInSection(dataSource)
    • (计算section中item的个数)
  • prepareLayout (layout)
    • (初始化布局)(调用了heightForItemAtIndexPath)
  • heightForItemAtIndexPath(delegate)
    • (多次调用计算每个Cell的高度)
  • collectionViewContentSize(layout)
    • (计算集合视图的大小)
  • layoutAttributesForElementsInRect(layout)(计算给定区域中cell的位置 ) + collectionViewContentSize
    • (每次调用layoutAttributesForElementsInRect之后还会调用一次这个方法,所以可以计算一次然后保存这个值ContentSize)
  • cellForItemAtIndexPath (datasource)
    • (获取当前可视区域的cell)

MKMasonryViewLayout.h

#import <UIKit/UIKit.h>

@class MKMasonryViewLayout;

@protocol MKMasonryViewLayoutDelegate <NSObject>
@required
- (CGFloat) collectionView:(UICollectionView*) collectionView
               layout:(MKMasonryViewLayout*) layout
 heightForItemAtIndexPath:(NSIndexPath*) indexPath;
@end

@interface MKMasonryViewLayout : UICollectionViewLayout
@property (nonatomic, assign) NSUInteger numberOfColumns;
@property (nonatomic, assign) CGFloat interItemSpacing;
@property (weak, nonatomic) IBOutlet id<MKMasonryViewLayoutDelegate> delegate;
@end

MKMasonryViewLayout.m

#import "MKMasonryViewLayout.h"

@interface MKMasonryViewLayout (/*Private Methods*/)
@property (nonatomic, strong) NSMutableDictionary *lastYValueForColumn;
@property (strong, nonatomic) NSMutableDictionary *layoutInfo;
@end

@implementation MKMasonryViewLayout

-(void) prepareLayout {


NSLog(@" prepareLayout ");

self.numberOfColumns = 3;//一行cell的数量
self.interItemSpacing = 12.5;//每行之间cell的间距

self.lastYValueForColumn = [NSMutableDictionary dictionary];
CGFloat currentColumn = 0;


CGFloat fullWidth = self.collectionView.frame.size.width;
CGFloat availableSpaceExcludingPadding = fullWidth - (self.interItemSpacing * (self.numberOfColumns + 1));
//计算cell宽度
CGFloat itemWidth = availableSpaceExcludingPadding / self.numberOfColumns;

//储存 UICollectionViewLayoutAttributes
self.layoutInfo = [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];
        
        UICollectionViewLayoutAttributes *itemAttributes =
        [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
        
        //计算物件的位置
        CGFloat x = self.interItemSpacing + (self.interItemSpacing + itemWidth) * currentColumn;
        CGFloat y = [self.lastYValueForColumn[@(currentColumn)] doubleValue];
        
        CGFloat height = [((id<MKMasonryViewLayoutDelegate>)self.collectionView.delegate)
                          collectionView:self.collectionView
                          layout:self
                          heightForItemAtIndexPath:indexPath];
        
        itemAttributes.frame = CGRectMake(x, y, itemWidth, height);
        y+= height;
        y += self.interItemSpacing;
        
        self.lastYValueForColumn[@(currentColumn)] = @(y);
        
        currentColumn ++;
        if(currentColumn == self.numberOfColumns) currentColumn = 0;
        //存入layoutInfo
        self.layoutInfo[indexPath] = itemAttributes;
    }
}
}

//计算给定区域中的物件 rect其实就是当前可视区域的rect
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {

NSLog(@" layoutAttributesForElementsInRect rect is %f %f %f %f",rect.origin.x,rect.origin.y,rect.size.width,rect.size.height);

NSMutableArray *allAttributes = [NSMutableArray arrayWithCapacity:self.layoutInfo.count];

[self.layoutInfo enumerateKeysAndObjectsUsingBlock:^(NSIndexPath *indexPath,
                                                     UICollectionViewLayoutAttributes *attributes,
                                                     BOOL *stop) {
    
    if (CGRectIntersectsRect(rect, attributes.frame)) {
        [allAttributes addObject:attributes];
    }
}];
return allAttributes;
}

//计算集合视图的大小 每次调用layoutAttributesForElementsInRect之后都会调用此方法,所以可以计算一次然后保存这个值ContentSize
-(CGSize) collectionViewContentSize {
NSLog(@" collectionViewContentSize " );
NSUInteger currentColumn = 0;
CGFloat maxHeight = 0;
do {
    CGFloat height = [self.lastYValueForColumn[@(currentColumn)] doubleValue];
    if(height > maxHeight)
        maxHeight = height;
    currentColumn ++;
} while (currentColumn < self.numberOfColumns);
NSLog(@" collectionViewContentSize %f %f ",self.collectionView.frame.size.width,maxHeight);
return CGSizeMake(self.collectionView.frame.size.width, maxHeight);
}

@end
原文地址:https://www.cnblogs.com/sunyanyan/p/5251271.html