23

Я пытаюсь добавить UIView между моими UICollectionViewCell s в моем UICollectionView, и я не знаю, как я мог это сделать. Я пытаюсь сделать что-то вроде этого:Как добавить представления между UICollectionViewCells в UICollectionView?

Screenshot

Я, вероятно, нужно писать пользовательские UICollectionViewLayout, но я не знаю, с чего начать.

ответ

45

Я изучил больше, как работает UICollectionViewLayout и выяснил, как его решить. У меня есть UICollectionReusableView подкласс OrangeView, который будет расположен между моими взглядами, чем я написал подкласс UICollectionViewFlowLayout под названием CategoriesLayout, который будет касаться моего макета.

Извините за большой блок кода, но вот как это выглядит:

@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 

Я также написал категорию с некоторыми методами, чтобы проверить, если путь индекс является последним в строке, в последняя строка или последней в разделе:

@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 

И это окончательный результат:

Final Result

+0

потрясающий, хороший дизайн! – Nikita

+0

Когда ячейка удалена снизу, этот код не удаляет разделитель, есть ли способ сделать это? – Weston

+1

@ Kronusdark попробуйте вызвать '-invalidateLayout' на макете просмотра коллекции, чтобы убедиться, что он перерисовывает все. Я не тестировал его, не уверен, работает ли он ... –

0

Если вы используете разделы и подходит для этого макета, вы можете использовать верхние и нижние колонтитулы раздела.

Но на основе вашей иллюстрации, похоже, вам просто нужно определить UICollectionViewCell, чтобы они содержали эти представления. Итак, где вы регистрируете свой класс:

[collectionView registerClass:[CollectionViewCell class] forCellWithReuseIdentifier:@"Cell"]; 

положить эти пограничные изображения в ячейки подкласса UICollectionView (в приведенном выше случае, «CollectionViewCell»). Это похоже на самый простой подход.

Вот один я использую:

- (id)initWithFrame:(CGRect)frame 
{ 
    self = [super initWithFrame:frame]; 
    if (self) 
    { 
     self.restorationIdentifier = @"Cell"; 
     self.backgroundColor = [UIColor clearColor]; 
     self.autoresizingMask = UIViewAutoresizingNone; 
     const CGFloat borderWidth = 3.0f; 
     UIView *bgView = [[UIView alloc] initWithFrame:frame]; 
     bgView.layer.borderColor = [UIColor blackColor].CGColor; 
     bgView.layer.borderWidth = borderWidth; 
     bgView.layer.cornerRadius = 6.0f; 
     self.selectedBackgroundView = bgView; 
    } 
    return self; 
} 
+0

Секция не присвоила. Мне нужно знать такие вещи, как если бы это была последняя ячейка в этой строке, я не должен отображать строку справа. Я хочу, чтобы Collection View мог быть повернут и, возможно, даже повторно использован на iPad, где расстояние между ячейками будет отличаться. –

+1

Вы можете контролировать расстояние и размер макетов (независимо от целевого устройства или ориентации) с помощью методов протокола UICollectionViewDelegateFlowLayout. Если вы правильно структурируете ячейку, нет никакой причины, по которой вы не можете контролировать граничные представления любым способом, который вы хотите на основе indexPath ячейки. – RegularExpression

0

Похоже, если ваш CollectionView фон был зеленый и белый contentView вы могли бы получить горизонталей с пространством между клетками minimumLineSpacing. Вертикальный зазор будет сложной частью, но если вы были креативны с вашим контентом и правильно поставили minimumInteritemSpacing, вы могли бы получить его.

+0

Это не сработает, если в последнем ряду нет предметов –

-1

Ничего себе. Это много кода в других ответах только для разделительной линии между строками.

Вот как я это решил. Сначала вам нужно будет добавить разделитель строк внутри ячейки. Удостоверьтесь, что вы продолжаете перетаскивать его, делая его шире, чем фактическая ширина ячейки, поэтому, если ширина вашей ячейки составляет 60p, разделительная линия будет равна 70.

@implementation CollectionViewController 
{ 
    NSArray *test; 
    int currentLocInRow; 
} 

внутри cellForItemAtIndexPath:

if((indexPath.row+1) % 4 == 0) 
    { 
     cell.clipsToBounds = YES; 
    } 
    else 
    { 
     cell.clipsToBounds = NO; 
    } 
    currentLocInRow++; 

    if([test count] - indexPath.row+1 < 4 - currentLocInRow) 
    { 
     cell.lineSeparator.alpha = 0; 
    } 
    else 
    { 
     cell.lineSeparator.alpha = 1; 
    } 
    if(currentLocInRow==4)currentLocInRow=0; 

enter image description here

Если вы хотите разделитель в конце представления коллекции, но есть шанс, что вы не получите 4 ячейки в последней строке вы можете добавить простой просмотр коллекций в виде нижнего колонтитула.

+0

Самая сложная часть - это получение разделителей между элементами внутри одной линии и заставить ее работать независимо от размера контейнера (когда вы вращаетесь или на iPad). –

+0

@MarcoPompei Мне нужно было только реализовать строки под строками для приложения, над которым я работал. Если мне когда-либо понадобится добавить разделители между элементами, я отправлю свое решение здесь (если я найду лучший) .. Большой вопрос. – Segev

+0

Хотя это меньше кода, это не то, что нужно поощрять. Это, очевидно, хак, который только «решает» 50% проблемы. – raulriera

-1

Сначала Вы должны установить край врезку для клеток сбора, после того, что вы должны установить рамку для просмотра сепаратора программного

- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section { 
    return UIEdgeInsetsMake(ITEM_SPACING, ITEM_SPACING, ITEM_SPACING, ITEM_SPACING); 
} 

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { 
    UIView *seperatorView = [[UIView alloc] initWithFrame:CGRectMake(cell.frame.origin.x, cell.frame.origin.y+cell.frame.size.height, cell.frame.size.width, 2)]; 
    seperatorView.backgroundColor = [UIColor grayColor]; 
    [collectionView addSubview:seperatorView]; 
    [collectionView bringSubviewToFront:seperatorView]; 
} 
+3

. Вы не должны добавлять subviews в collectionView таким образом, они никогда не будут удалены, а при прокрутке это добавит все больше разделителей. –

+0

Его работа хорошая для меня. Я не видел добавления дополнительных разделителей во время прокрутки. В любом случае спасибо за ваш комментарий –

+0

Вы не увидите их, потому что они непрозрачны и сложены друг на друга, попробуйте установить цвет с помощью альфы, и вы увидите. –

Смежные вопросы