集合视图和它的布局都不会告诉你项目的“行号”。您必须自己计算。
如果您的所有测量值都是统一的(如果您没有实现任何 UICollectionViewDelegateFlowLayout 方法就是这种情况),您可以很容易地计算它。
有几个地方可以进行计算并分配颜色。我将向您展示执行此操作的“正确”位置:在布局管理器中。
“Knowing When to Subclass the Flow Layout” section of the Collection View Programming Guide for iOS 告诉你需要做的基本事情,但它非常简单,所以我将引导你完成它。
注意:由于layoutAttributes 是一个相当麻烦的标识符,我通常使用pose 来代替。
UICollectionViewLayoutAttributes 子类
首先,我们需要一种将背景颜色从布局管理器传递到单元格的方法。正确的做法是继承UICollectionViewLayoutAttributes。界面只增加了一个属性:
@interface MyLayoutAttributes : UICollectionViewLayoutAttributes
@property (nonatomic, strong) UIColor *backgroundColor;
@end
实现需要实现NSCopying协议:
@implementation MyLayoutAttributes
- (instancetype)copyWithZone:(NSZone *)zone {
MyLayoutAttributes *copy = [super copyWithZone:zone];
copy.backgroundColor = self.backgroundColor;
return copy;
}
@end
UICollectionViewCell 子类
接下来,单元格需要使用backgroundColor 属性。您可能已经有一个UICollectionViewCell 子类。你需要在你的子类中实现applyLayoutAttributes:,像这样:
@implementation MyCell
- (void)applyLayoutAttributes:(MyLayoutAttributes *)pose {
[super applyLayoutAttributes:pose];
if (!self.backgroundView) {
self.backgroundView = [[UIView alloc] init];
}
self.backgroundView.backgroundColor = pose.backgroundColor;
}
@end
UICollectionViewFlowLayout 子类
现在您需要创建一个UICollectionViewFlowLayout 的子类,它使用MyLayoutAttributes 而不是UICollectionViewLayoutAttributes,并正确设置每个MyLayoutAttributes 的backgroundColor。让我们将接口定义为具有一个属性,该属性是分配给行的颜色数组:
@interface MyLayout : UICollectionViewFlowLayout
@property (nonatomic, copy) NSArray *rowColors;
@end
我们在实现中需要做的第一件事是指定我们希望它使用的布局属性类:
@implementation MyLayout
+ (Class)layoutAttributesClass {
return [MyLayoutAttributes class];
}
接下来,我们需要重写UICollectionViewLayout的两个方法来设置每个pose的backgroundColor属性。我们调用super来获取pose集合,然后使用辅助方法设置背景颜色:
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {
NSArray *poses = [super layoutAttributesForElementsInRect:rect];
[self assignBackgroundColorsToPoses:poses];
return poses;
}
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath {
MyLayoutAttributes *pose = (MyLayoutAttributes *)[super layoutAttributesForItemAtIndexPath:indexPath];
[self assignBackgroundColorsToPoses:@[ pose ]];
return pose;
}
这是实际分配背景颜色的方法:
- (void)assignBackgroundColorsToPoses:(NSArray *)poses {
NSArray *rowColors = self.rowColors;
int rowColorsCount = rowColors.count;
if (rowColorsCount == 0)
return;
UIEdgeInsets insets = self.sectionInset;
CGFloat lineSpacing = self.minimumLineSpacing;
CGFloat rowHeight = self.itemSize.height + lineSpacing;
for (MyLayoutAttributes *pose in poses) {
CGFloat y = pose.frame.origin.y;
NSInteger section = pose.indexPath.section;
y -= section * (insets.top + insets.bottom) + insets.top;
y += section * lineSpacing; // Fudge: assume each prior section had at least one cell
int row = floorf(y / rowHeight);
pose.backgroundColor = rowColors[row % rowColorsCount];
}
}
请注意,此方法做了几个假设:
- 它假定滚动方向是垂直的。
- 假定所有项目的大小相同。
- 它假定所有部分都具有相同的插入和行距。
- 假设每个部分至少有一项。
最后一个假设的原因是一个section中的所有行后面都有最小行间距,除了是最后一行,后面是底部的section inset。我需要知道当前项目行之前有多少行。我尝试通过将 Y 坐标除以一行的高度来做到这一点……但每个部分的最后一行比其他部分短。因此,捏造。
应用你的新类
无论如何,现在我们需要使用这些新类。
首先,我们需要使用MyLayout 而不是UICollectionViewFlowLayout。如果您在代码中设置集合视图,只需创建一个而不是 MyLayout 并将其分配给集合视图。如果您在情节提要中进行设置,请找到集合视图的布局(它在情节提要大纲中作为集合视图的子级)并将其自定义类设置为 MyLayout。
其次,我们需要为布局分配一组颜色。如果您使用故事板,您可能希望在viewDidLoad 中执行此操作。您可以向集合视图询问其布局,然后将其转换为MyLayout。我更喜欢使用正确类型的插座,连接到情节提要中的布局对象。
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.layout.rowColors = @[
[UIColor lightGrayColor],
[UIColor cyanColor],
];
}
结果
如果一切设置正确,您将得到如下结果:
横向显示如下:
我已经把我的测试项目in this github repository。