【发布时间】:2015-03-04 15:15:35
【问题描述】:
所以我正在尝试使用 UICollectionView 构建类似 EPG 的视图。这是我第一次使用这个框架。类似this。
我很快就注意到我需要实现一个自定义布局来实现这个 EPG。我关注了这个guide。
我需要“粘贴”集合视图的第一列和第一行,并让 EPG 水平和垂直滚动。虽然本教程很棒,但我在调整它以适应我的规范时遇到了问题。即本教程将每个部分中的列声明为等宽。而我要求我的列在每个部分中都是动态的。例如:每行本身就是一个部分,因此每行的高度将保持不变,但每行中的单元格将具有不同的宽度,具体取决于程序在每个单独的集合视图单元格中显示的长度。
任何人都可以帮助我或指出正确的方向如何使用以下代码实现这一点:
- (void)prepareLayout
{
if ([self.collectionView numberOfSections] == 0) {
return;
}
NSUInteger column = 0; // Current column inside row
CGFloat xOffset = 0.0;
CGFloat yOffset = 0.0;
CGFloat contentWidth = 0.0; // To determine the contentSize
CGFloat contentHeight = 0.0; // To determine the contentSize
if (self.itemAttributes.count > 0) { // We don't enter in this if statement the first time, we enter the following times
for (int section = 0; section < [self.collectionView numberOfSections]; section++) {
NSUInteger numberOfItems = [self.collectionView numberOfItemsInSection:section];
for (NSUInteger index = 0; index < numberOfItems; index++) {
if (section != 0 && index != 0) { // This is a content cell that shouldn't be sticked
continue;
}
UICollectionViewLayoutAttributes *attributes = [self layoutAttributesForItemAtIndexPath:[NSIndexPath indexPathForItem:index inSection:section]];
if (section == 0) { // We stick the first row
CGRect frame = attributes.frame;
frame.origin.y = self.collectionView.contentOffset.y;
attributes.frame = frame;
}
if (index == 0) { // We stick the first column
CGRect frame = attributes.frame;
frame.origin.x = self.collectionView.contentOffset.x;
attributes.frame = frame;
}
}
}
return;
}
// The following code is only executed the first time we prepare the layout
self.itemAttributes = [@[] mutableCopy];
self.itemsSize = [@[] mutableCopy];
// Tip: If we don't know the number of columns we can call the following method and use the NSUInteger object instead of the NUMBEROFCOLUMNS macro
// NSUInteger numberOfItems = [self.collectionView numberOfItemsInSection:section];
// We calculate the item size of each column
if (self.itemsSize.count != NUMBEROFCOLUMNS) {
[self calculateItemsSize];
}
// We loop through all items
for (int section = 0; section < [self.collectionView numberOfSections]; section++) {
NSMutableArray *sectionAttributes = [@[] mutableCopy];
for (NSUInteger index = 0; index < NUMBEROFCOLUMNS; index++) {
CGSize itemSize = [self.itemsSize[index] CGSizeValue];
// We create the UICollectionViewLayoutAttributes object for each item and add it to our array.
// We will use this later in layoutAttributesForItemAtIndexPath:
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:index inSection:section];
UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
attributes.frame = CGRectIntegral(CGRectMake(xOffset, yOffset, itemSize.width, itemSize.height));
if (section == 0 && index == 0) {
attributes.zIndex = 1024; // Set this value for the first item (Sec0Row0) in order to make it visible over first column and first row
} else if (section == 0 || index == 0) {
attributes.zIndex = 1023; // Set this value for the first row or section in order to set visible over the rest of the items
}
if (section == 0) {
CGRect frame = attributes.frame;
frame.origin.y = self.collectionView.contentOffset.y;
attributes.frame = frame; // Stick to the top
}
if (index == 0) {
CGRect frame = attributes.frame;
frame.origin.x = self.collectionView.contentOffset.x;
attributes.frame = frame; // Stick to the left
}
[sectionAttributes addObject:attributes];
xOffset = xOffset+itemSize.width;
column++;
// Create a new row if this was the last column
if (column == NUMBEROFCOLUMNS) {
if (xOffset > contentWidth) {
contentWidth = xOffset;
}
// Reset values
column = 0;
xOffset = 0;
yOffset += itemSize.height;
}
}
[self.itemAttributes addObject:sectionAttributes];
}
// Get the last item to calculate the total height of the content
UICollectionViewLayoutAttributes *attributes = [[self.itemAttributes lastObject] lastObject];
contentHeight = attributes.frame.origin.y+attributes.frame.size.height;
self.contentSize = CGSizeMake(contentWidth, contentHeight);
}
- (CGSize)collectionViewContentSize
{
return self.contentSize;
}
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
{
return self.itemAttributes[indexPath.section][indexPath.row];
}
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
{
NSMutableArray *attributes = [@[] mutableCopy];
for (NSArray *section in self.itemAttributes) {
[attributes addObjectsFromArray:[section filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(UICollectionViewLayoutAttributes *evaluatedObject, NSDictionary *bindings) {
return CGRectIntersectsRect(rect, [evaluatedObject frame]);
}]]];
}
return attributes;
}
- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds
{
return YES; // Set this to YES to call prepareLayout on every scroll
}
- (CGSize)sizeForItemWithColumnIndex:(NSUInteger)columnIndex
{
NSLog(@"sizeForItemWithColumnIndex");
NSString *text;
for (NSUInteger index = 0; index < NUMBEROFCOLUMNS; index++) {
text = @"asdf";
}
CGSize size = [text sizeWithAttributes: @{NSFontAttributeName:[UIFont fontWithName:@"HelveticaNeue" size:15]}];
NSLog(@"Size of %@", NSStringFromCGSize(size));
if (columnIndex == 0) {
size.width += 1; // In our design the first column should be the widest one
}
return CGSizeMake([@(size.width + 50) floatValue], 40); // Extra space of 9px for all the items
}
- (void)calculateItemsSize
{
NSLog(@"calculate item size");
for (NSUInteger index = 0; index < NUMBEROFCOLUMNS; index++) {
if (self.itemsSize.count <= index) {
CGSize itemSize = [self sizeForItemWithColumnIndex:index];
NSValue *itemSizeValue = [NSValue valueWithCGSize:itemSize];
[self.itemsSize addObject:itemSizeValue];
}
}
}
@end
【问题讨论】:
标签: ios objective-c uicollectionview uicollectionviewlayout