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
@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 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)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

posted @ 2016-03-07 17:33  孙焱焱  阅读(778)  评论(0)    收藏  举报