Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to add views between UICollectionViewCells in a UICollectionView?

Tags:

I'm trying to add UIViews between my UICollectionViewCells in my UICollectionView and I don't know how I could do that. I'm trying to accomplish something like this:

Screenshot

I'll probably need to write a custom UICollectionViewLayout, but I don't really know where to start.

like image 325
Marco Pompei Avatar asked Apr 01 '13 19:04

Marco Pompei


People also ask

What is UICollectionView flow layout?

Overview. A flow layout is a type of collection view layout. Items in the collection view flow from one row or column (depending on the scrolling direction) to the next, with each row containing as many cells as will fit. Cells can be the same sizes or different sizes.

How does UICollectionView work?

The collection view presents items onscreen using a cell, which is an instance of the UICollectionViewCell class that your data source configures and provides. In addition to its cells, a collection view can present data using other types of views.


1 Answers

I studied more of how UICollectionViewLayouts work and figured out how to solve it. I have an UICollectionReusableView subclass called OrangeView that will be positioned between my views, than I wrote an UICollectionViewFlowLayout subclass called CategoriesLayout that will deal with my layout.

Sorry for the big block of code, but here is how it looks like:

@implementation CategoriesLayout  - (void)prepareLayout {     // Registers my decoration views.     [self registerClass:[OrangeView class] forDecorationViewOfKind:@"Vertical"];     [self registerClass:[OrangeView class] forDecorationViewOfKind:@"Horizontal"]; }  - (UICollectionViewLayoutAttributes *)layoutAttributesForDecorationViewOfKind:(NSString *)decorationViewKind atIndexPath:(NSIndexPath *)indexPath {     // Prepare some variables.     NSIndexPath *nextIndexPath = [NSIndexPath indexPathForItem:indexPath.row+1 inSection:indexPath.section];      UICollectionViewLayoutAttributes *cellAttributes = [self layoutAttributesForItemAtIndexPath:indexPath];     UICollectionViewLayoutAttributes *nextCellAttributes = [self layoutAttributesForItemAtIndexPath:nextIndexPath];      UICollectionViewLayoutAttributes *layoutAttributes = [UICollectionViewLayoutAttributes layoutAttributesForDecorationViewOfKind:decorationViewKind withIndexPath:indexPath];      CGRect baseFrame = cellAttributes.frame;     CGRect nextFrame = nextCellAttributes.frame;      CGFloat strokeWidth = 4;     CGFloat spaceToNextItem = 0;     if (nextFrame.origin.y == baseFrame.origin.y)         spaceToNextItem = (nextFrame.origin.x - baseFrame.origin.x - baseFrame.size.width);      if ([decorationViewKind isEqualToString:@"Vertical"]) {         CGFloat padding = 10;          // Positions the vertical line for this item.         CGFloat x = baseFrame.origin.x + baseFrame.size.width + (spaceToNextItem - strokeWidth)/2;         layoutAttributes.frame = CGRectMake(x,                                             baseFrame.origin.y + padding,                                             strokeWidth,                                             baseFrame.size.height - padding*2);     } else {         // Positions the horizontal line for this item.         layoutAttributes.frame = CGRectMake(baseFrame.origin.x,                                             baseFrame.origin.y + baseFrame.size.height,                                             baseFrame.size.width + spaceToNextItem,                                             strokeWidth);     }      layoutAttributes.zIndex = -1;     return layoutAttributes; }  - (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {     NSArray *baseLayoutAttributes = [super layoutAttributesForElementsInRect:rect];     NSMutableArray * layoutAttributes = [baseLayoutAttributes mutableCopy];      for (UICollectionViewLayoutAttributes *thisLayoutItem in baseLayoutAttributes) {         if (thisLayoutItem.representedElementCategory == UICollectionElementCategoryCell) {             // Adds vertical lines when the item isn't the last in a section or in line.             if (!([self indexPathLastInSection:thisLayoutItem.indexPath] ||                   [self indexPathLastInLine:thisLayoutItem.indexPath])) {                 UICollectionViewLayoutAttributes *newLayoutItem = [self layoutAttributesForDecorationViewOfKind:@"Vertical" atIndexPath:thisLayoutItem.indexPath];                 [layoutAttributes addObject:newLayoutItem];             }              // Adds horizontal lines when the item isn't in the last line.             if (![self indexPathInLastLine:thisLayoutItem.indexPath]) {                 UICollectionViewLayoutAttributes *newHorizontalLayoutItem = [self layoutAttributesForDecorationViewOfKind:@"Horizontal" atIndexPath:thisLayoutItem.indexPath];                 [layoutAttributes addObject:newHorizontalLayoutItem];             }         }     }      return layoutAttributes; }  @end 

I also wrote a category with some methods to check if an index path is the last in a line, in the last line or the last in a section:

@implementation UICollectionViewFlowLayout (Helpers)  - (BOOL)indexPathLastInSection:(NSIndexPath *)indexPath {     NSInteger lastItem = [self.collectionView.dataSource collectionView:self.collectionView numberOfItemsInSection:indexPath.section] -1;     return  lastItem == indexPath.row; }  - (BOOL)indexPathInLastLine:(NSIndexPath *)indexPath {     NSInteger lastItemRow = [self.collectionView.dataSource collectionView:self.collectionView numberOfItemsInSection:indexPath.section] -1;     NSIndexPath *lastItem = [NSIndexPath indexPathForItem:lastItemRow inSection:indexPath.section];     UICollectionViewLayoutAttributes *lastItemAttributes = [self layoutAttributesForItemAtIndexPath:lastItem];     UICollectionViewLayoutAttributes *thisItemAttributes = [self layoutAttributesForItemAtIndexPath:indexPath];      return lastItemAttributes.frame.origin.y == thisItemAttributes.frame.origin.y; }  - (BOOL)indexPathLastInLine:(NSIndexPath *)indexPath {     NSIndexPath *nextIndexPath = [NSIndexPath indexPathForItem:indexPath.row+1 inSection:indexPath.section];      UICollectionViewLayoutAttributes *cellAttributes = [self layoutAttributesForItemAtIndexPath:indexPath];     UICollectionViewLayoutAttributes *nextCellAttributes = [self layoutAttributesForItemAtIndexPath:nextIndexPath];      return !(cellAttributes.frame.origin.y == nextCellAttributes.frame.origin.y); }  @end 

And this is the final result:

Final Result

like image 98
Marco Pompei Avatar answered Nov 25 '22 14:11

Marco Pompei