【问题标题】:How to add views between UICollectionViewCells in a UICollectionView?如何在 UICollectionView 中的 UICollectionViewCells 之间添加视图?
【发布时间】:2013-04-01 19:03:21
【问题描述】:

我正在尝试在UICollectionView 中的UICollectionViewCells 之间添加UIViews,但我不知道该怎么做。我正在尝试完成这样的事情:

我可能需要编写一个自定义的UICollectionViewLayout,但我真的不知道从哪里开始。

【问题讨论】:

    标签: iphone ios objective-c uicollectionview uicollectionviewcell


    【解决方案1】:

    我更多地研究了UICollectionViewLayouts 的工作原理,并想出了如何解决它。我有一个名为OrangeViewUICollectionReusableView 子类,它将位于我的视图之间,而不是我编写了一个名为CategoriesLayoutUICollectionViewFlowLayout 子类来处理我的布局。

    抱歉,代码块很大,但它是这样的:

    @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
    

    这是最终的结果:

    【讨论】:

    • 当从底部移除一个单元格时,这段代码不会移除分隔符,有没有办法做到这一点?
    • @Kronusdark 尝试在集合视图布局上调用 -invalidateLayout 以查看它是否强制重绘所有内容。我还没有测试过,不确定它是否有效……
    • 这行得通,但它会挂掉一秒钟,我将不得不与时间安排一起玩。非常感谢您的快速回复
    • @Kronusdark 是的,我认为它可能会发生。我检查了UICollectionViewLayout Class Reference,检查了Methods to Override,其中六个涉及添加和删除项目,实施它们应该可以工作。也许我回家后会尝试更新此代码,但我什么都不能保证。
    • 太难懂了,如果有源码项目下载链接就更好了
    【解决方案2】:

    如果您正在使用节并且布局适合它,则可以使用节页眉和页脚。

    但根据您的说明,您似乎只需要定义 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;
    }
    

    【讨论】:

    • 部分没有被占用。我需要知道这是否是该行的最后一个单元格,我不应该在右侧显示该行。我想要一个可以旋转的集合视图,甚至可以在 iPad 上重复使用,其中单元格之间的距离会不同。
    • 您可以通过 UICollectionViewDelegateFlowLayout 协议的方法控制布局的间距和大小(无论目标设备或方向)。如果您正确构建单元格,则没有理由无法根据单元格的 indexPath 以任何您希望的方式控制边框视图。
    【解决方案3】:

    看起来如果您的 collectionView 背景是绿色而 contentView 是白色的,您可以获得水平方向,单元格 minimumLineSpacing 之间有一个空格。垂直间隙将是棘手的部分,但如果您对 contentView 有创意并仔细设置minimumInteritemSpacing,您可以得到它。

    【讨论】:

      【解决方案4】:

      哇。其他答案中有很多代码只是用于行之间的分隔线..

      我就是这样解决的。首先,您需要在单元格内添加行分隔符。确保您一直拖动它,使其比实际单元格宽度更宽,因此如果您的单元格宽度为 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;
      

      如果您想在集合视图的末尾添加一个分隔符,但最后一行可能没有 4 个单元格,您可以添加一个简单的集合可重用视图作为页脚。

      【讨论】:

      • 最棘手的部分是在同一行内的项目之间获取分隔符,并使其独立于容器大小(当您旋转或在 iPad 上)工作。
      • @MarcoPompei 我只需要在我正在开发的应用程序的行下实现行。如果我需要在项目之间添加分隔符,我会在这里发布我的解决方案(如果我能找到更好的解决方案..)好问题。
      • 虽然代码少,但不应该鼓励这样做。这显然是一个只能“解决”50% 问题的 hack
      猜你喜欢
      • 2019-01-18
      • 1970-01-01
      • 2018-02-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-09-23
      • 1970-01-01
      相关资源
      最近更新 更多