所以我试图使用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
答案 0 :(得分:0)
好的,我自己从头开始回答这个问题。在准备布局之前,我将程序和通道信息的xml Web服务加载到SQLite数据库中。使用第三方库FMDB拉出行,并根据每个程序运行的分钟数计算每个单元的帧(xPos,yPos,cellWidth,cellHeight)。 (除了包含时间轴的第一部分,以及每个部分中包含每个特定通道的图标的第一个项目。)我保存到字典中的每个计算都可以参考布局。
- (void)calculateFramesForAllPrograms {
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:0];
NSInteger counterForDatabaseRow = 0;
for (NSInteger section = 0; section < numOfChannels + EXTRA_ROW_FOR_TIME; section++) {
if(section==0){
for (NSInteger items = 0; items <=HOURS_IN_A_DAY + EXTRA_ROW_FOR_TIME; items++){
if(items==0){
CGRect frame = CGRectMake(xPos, yPos, TILE_HEIGHT, TILE_HEIGHT);
NSString *rectString = NSStringFromCGRect(frame);
indexPath = [NSIndexPath indexPathForItem:items inSection:section];
//NSLog(@"INDEX PATH %@", indexPath);
self.frameInfo[indexPath] = rectString;
xPos = xPos+TILE_HEIGHT;
}else {
CGRect frame = CGRectMake(xPos, yPos, self.timeTile.width, self.timeTile.height);
NSString *rectString = NSStringFromCGRect(frame);
indexPath = [NSIndexPath indexPathForItem:items inSection:section];
//NSLog(@"INDEX PATH %@", indexPath);
self.frameInfo[indexPath] = rectString;
xPos = xPos+self.timeTile.width;
}
}
} else {
xPos = 0;
//NSLog(@"SECTION COUNT: %lu", section);
NSString *query = [NSString stringWithFormat:@"SELECT COUNT(channel_code) AS channels FROM epg WHERE channel_code='%@", self.channelCodes[section-EXTRA_ROW_FOR_TIME]];
NSString *completedQuery = [query stringByAppendingString:@"'"];
//NSLog(@"string %@", completedQuery);
db = [FMDatabase databaseWithPath:[Utility getDatabasePath]];
[db open];
NSUInteger itemCount = [db intForQuery:completedQuery];
for (NSInteger item = 0; item <itemCount+EXTRA_ROW_FOR_TIME; item++) {
//NSLog(@"Item: %lu Item: %lu", item, itemCount);
if(item==0){
CGRect frame = CGRectMake(xPos, yPos, TILE_HEIGHT, TILE_HEIGHT);
NSString *rectString = NSStringFromCGRect(frame);
indexPath = [NSIndexPath indexPathForItem:item inSection:section];
//NSLog(@"INDEX PATH %@", indexPath);
self.frameInfo[indexPath] = rectString;
xPos = xPos+TILE_HEIGHT;
}else {
if (item==itemCount){
//NSLog(@"LAST ITEM %@", self.endTimes[counter]);
isLastItem = TRUE;
}
CGSize tileSize = [self sizeForProgramTile:counterForDatabaseRow];
//NSLog(@"TILE SIZE RETURNED %@", NSStringFromCGSize(tileSize));
CGRect frame = CGRectMake(xPos, yPos, tileSize.width, tileSize.height);
NSString *rectString = NSStringFromCGRect(frame);
indexPath = [NSIndexPath indexPathForItem:item inSection:section];
//NSLog(@"INDEX PATH %@", indexPath);
self.frameInfo[indexPath] = rectString;
xPos = xPos+tileSize.width;
counterForDatabaseRow++;
}
}
}
yPos += TILE_HEIGHT;
}
//NSLog(@"FRAME INFO %@", self.frameInfo);
}