Files
Ash_AWord/Pods/PSTCollectionView/PSTCollectionView/PSTGridLayoutRow.m
T
2015-04-02 09:37:44 +08:00

194 lines
7.5 KiB
Objective-C

//
// PSTGridLayoutRow.m
// PSPDFKit
//
// Copyright (c) 2012-2013 Peter Steinberger. All rights reserved.
//
#import "PSTCollectionView.h"
#import "PSTGridLayoutRow.h"
#import "PSTGridLayoutSection.h"
#import "PSTGridLayoutItem.h"
#import "PSTGridLayoutInfo.h"
@interface PSTGridLayoutRow () {
NSMutableArray *_items;
BOOL _isValid;
int _verticalAlignement;
int _horizontalAlignement;
}
@property (nonatomic, strong) NSArray *items;
@end
@implementation PSTGridLayoutRow
///////////////////////////////////////////////////////////////////////////////////////////
#pragma mark - NSObject
- (id)init {
if ((self = [super init])) {
_items = [NSMutableArray new];
}
return self;
}
- (NSString *)description {
return [NSString stringWithFormat:@"<%@: %p frame:%@ index:%ld items:%@>", NSStringFromClass(self.class), self, NSStringFromCGRect(self.rowFrame), (long)self.index, self.items];
}
///////////////////////////////////////////////////////////////////////////////////////////
#pragma mark - Public
- (void)invalidate {
_isValid = NO;
_rowSize = CGSizeZero;
_rowFrame = CGRectZero;
}
- (NSArray *)itemRects {
return [self layoutRowAndGenerateRectArray:YES];
}
- (void)layoutRow {
[self layoutRowAndGenerateRectArray:NO];
}
- (NSArray *)layoutRowAndGenerateRectArray:(BOOL)generateRectArray {
NSMutableArray *rects = generateRectArray ? [NSMutableArray array] : nil;
if (!_isValid || generateRectArray) {
// properties for aligning
BOOL isHorizontal = self.section.layoutInfo.horizontal;
BOOL isLastRow = self.section.indexOfImcompleteRow == self.index;
PSTFlowLayoutHorizontalAlignment horizontalAlignment = [self.section.rowAlignmentOptions[isLastRow ? PSTFlowLayoutLastRowHorizontalAlignmentKey : PSTFlowLayoutCommonRowHorizontalAlignmentKey] integerValue];
// calculate space that's left over if we would align it from left to right.
CGFloat leftOverSpace = self.section.layoutInfo.dimension;
if (isHorizontal) {
leftOverSpace -= self.section.sectionMargins.top + self.section.sectionMargins.bottom;
}else {
leftOverSpace -= self.section.sectionMargins.left + self.section.sectionMargins.right;
}
// calculate the space that we have left after counting all items.
// UICollectionView is smart and lays out items like they would have been placed on a full row
// So we need to calculate the "usedItemCount" with using the last item as a reference size.
// This allows us to correctly justify-place the items in the grid.
NSInteger usedItemCount = 0;
NSInteger itemIndex = 0;
CGFloat spacing = isHorizontal ? self.section.verticalInterstice : self.section.horizontalInterstice;
// the last row should justify as if it is filled with more (invisible) items so that the whole
// UICollectionView feels more like a grid than a random line of blocks
while (itemIndex < self.itemCount || isLastRow) {
CGFloat nextItemSize;
// first we need to find the size (width/height) of the next item to fit
if (!self.fixedItemSize) {
PSTGridLayoutItem *item = self.items[(NSUInteger)MIN(itemIndex, self.itemCount - 1)];
nextItemSize = isHorizontal ? item.itemFrame.size.height : item.itemFrame.size.width;
}else {
nextItemSize = isHorizontal ? self.section.itemSize.height : self.section.itemSize.width;
}
// the first item does not add a separator spacing,
// every one afterwards in the same row will need this spacing constant
if (itemIndex > 0) {
nextItemSize += spacing;
}
// check to see if we can at least fit an item (+separator if necessary)
if (leftOverSpace < nextItemSize) {
break;
}
// we need to maintain the leftover space after the maximum amount of items have
// occupied, so we know how to adjust equal spacing among all the items in a row
leftOverSpace -= nextItemSize;
itemIndex++;
usedItemCount = itemIndex;
}
// push everything to the right if right-aligning and divide in half for centered
// currently there is no public API supporting this behavior
CGPoint itemOffset = CGPointZero;
if (horizontalAlignment == PSTFlowLayoutHorizontalAlignmentRight) {
itemOffset.x += leftOverSpace;
}else if (horizontalAlignment == PSTFlowLayoutHorizontalAlignmentCentered ||
(horizontalAlignment == PSTFlowLayoutHorizontalAlignmentJustify && usedItemCount == 1)) {
// Special case one item row to split leftover space in half
itemOffset.x += leftOverSpace / 2;
}
// calculate the justified spacing among all items in a row if we are using
// the default PSTFlowLayoutHorizontalAlignmentJustify layout
CGFloat interSpacing = usedItemCount <= 1 ? 0 : leftOverSpace / (CGFloat)(usedItemCount - 1);
// calculate row frame as union of all items
CGRect frame = CGRectZero;
CGRect itemFrame = (CGRect){.size=self.section.itemSize};
for (itemIndex = 0; itemIndex < self.itemCount; itemIndex++) {
PSTGridLayoutItem *item = nil;
if (!self.fixedItemSize) {
item = self.items[(NSUInteger)itemIndex];
itemFrame = [item itemFrame];
}
// depending on horizontal/vertical for an item size (height/width),
// we add the minimum separator then an equally distributed spacing
// (since our default mode is justify) calculated from the total leftover
// space divided by the number of intervals
if (isHorizontal) {
itemFrame.origin.y = itemOffset.y;
itemOffset.y += itemFrame.size.height + self.section.verticalInterstice;
if (horizontalAlignment == PSTFlowLayoutHorizontalAlignmentJustify) {
itemOffset.y += interSpacing;
}
}else {
itemFrame.origin.x = itemOffset.x;
itemOffset.x += itemFrame.size.width + self.section.horizontalInterstice;
if (horizontalAlignment == PSTFlowLayoutHorizontalAlignmentJustify) {
itemOffset.x += interSpacing;
}
}
item.itemFrame = itemFrame; // might call nil; don't care
[rects addObject:[NSValue valueWithCGRect:itemFrame]];
frame = CGRectUnion(frame, itemFrame);
}
_rowSize = frame.size;
// _rowFrame = frame; // set externally
_isValid = YES;
}
return rects;
}
- (void)addItem:(PSTGridLayoutItem *)item {
[_items addObject:item];
item.rowObject = self;
[self invalidate];
}
- (PSTGridLayoutRow *)snapshot {
PSTGridLayoutRow *snapshotRow = [self.class new];
snapshotRow.section = self.section;
snapshotRow.items = self.items;
snapshotRow.rowSize = self.rowSize;
snapshotRow.rowFrame = self.rowFrame;
snapshotRow.index = self.index;
snapshotRow.complete = self.complete;
snapshotRow.fixedItemSize = self.fixedItemSize;
snapshotRow.itemCount = self.itemCount;
return snapshotRow;
}
- (PSTGridLayoutRow *)copyFromSection:(PSTGridLayoutSection *)section {
return nil; // ???
}
- (NSInteger)itemCount {
if (self.fixedItemSize) {
return _itemCount;
}else {
return (NSInteger)self.items.count;
}
}
@end