如何在 UICollectionView 中的 UICollectionViewCells 之间添加视图?
Posted
技术标签:
【中文标题】如何在 UICollectionView 中的 UICollectionViewCells 之间添加视图?【英文标题】:How to add views between UICollectionViewCells in a UICollectionView? 【发布时间】:2013-04-01 19:03:21 【问题描述】:我正在尝试在UICollectionView
中的UICollectionViewCell
s 之间添加UIView
s,但我不知道该怎么做。我正在尝试完成这样的事情:
我可能需要编写一个自定义的UICollectionViewLayout
,但我真的不知道从哪里开始。
【问题讨论】:
【参考方案1】:我更多地研究了UICollectionViewLayout
s 的工作原理,并想出了如何解决它。我有一个名为OrangeView
的UICollectionReusableView
子类,它将位于我的视图之间,而不是我编写了一个名为CategoriesLayout
的UICollectionViewFlowLayout
子类来处理我的布局。
抱歉,代码块很大,但它是这样的:
@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以上是关于如何在 UICollectionView 中的 UICollectionViewCells 之间添加视图?的主要内容,如果未能解决你的问题,请参考以下文章
deleteItemsAtIndexPaths 中的 UICollectionView 断言失败
UICollectionView如何删除单元格(相当于commitEditingStyle)?
如何在 UITableView 内的 UICollectionView 内获取数组数组并返回正确数量的项目?
ScrollView 或 UICollectionView 中的 UItableViews? [关闭]
如何以编程方式快速创建 uicollectionview(没有情节提要)
如何在 UIView(不是 UITableView、UICollectionView、UIScrollView)上添加 Pull-to-refresh