问题描述
我知道这对于 UITableViewCells 来说相当容易,但我不确定如何使用 UICollectionView 来解决这个问题.
编辑.图片以供澄清.单元格的文本内容在这里不一样,但它们应该是一样的.横向:
纵向:
我尝试根据 cellForItemAtIndexPath:
方法中的索引路径的 row 属性,用单元格的背景颜色天真地切换单元格文本标签的颜色.然而,Index Path 的 row 属性在 UICollectionViewFlowLayout 中并不是真正的一行.
集合视图和它的布局都不会告诉你项目的行号".您必须自己计算.
如果你所有的测量都是统一的(如果你没有实现任何 UICollectionViewDelegateFlowLayout
方法就是这种情况),你可以很容易地计算它.
有几个地方可以进行计算并分配颜色.我将向您展示执行此操作的正确"位置:在布局管理器中.
横向显示如下:
我已将我的测试项目 放在这个 github 存储库中.
I know this is fairly easy for UITableViewCells but I'm not sure how to approach this using a UICollectionView.
EDIT. Pictures for clarification. Text content of the cells are not the same here but they should be.In landscape:
In portrait:
I tried to naively switch the color of my cell's text label with the cell's background color based on the index path's row property in the cellForItemAtIndexPath:
method. However Index Path's row property isn't really a row in UICollectionViewFlowLayout.
Neither the collection view nor its layout will tell you a "row number" for items. You have to compute it yourself.
If all of your measurements are uniform (which is the case if you didn't implement any UICollectionViewDelegateFlowLayout
methods), you can compute it pretty easily.
There are a few places you could do the computation and assign the color. I'm going to show you the "proper" place to do it: in the layout manager.
The "Knowing When to Subclass the Flow Layout" section of the Collection View Programming Guide for iOS tells you the basic things you need to do, but it's pretty bare bones, so I'll walk you through it.
Note: since layoutAttributes
is a pretty cumbersome identifier, I usually use pose
instead.
UICollectionViewLayoutAttributes
subclass
First of all, we need a way to pass the background color from the layout manager to the cell. The right way to do that is by subclassing UICollectionViewLayoutAttributes
. The interface just adds one property:
@interface MyLayoutAttributes : UICollectionViewLayoutAttributes
@property (nonatomic, strong) UIColor *backgroundColor;
@end
The implementation needs to implement the NSCopying
protocol:
@implementation MyLayoutAttributes
- (instancetype)copyWithZone:(NSZone *)zone {
MyLayoutAttributes *copy = [super copyWithZone:zone];
copy.backgroundColor = self.backgroundColor;
return copy;
}
@end
UICollectionViewCell
subclass
Next, the cell needs to use that backgroundColor
attributes. You probably already have a UICollectionViewCell
subclass. You need to implement applyLayoutAttributes:
in your subclass, like this:
@implementation MyCell
- (void)applyLayoutAttributes:(MyLayoutAttributes *)pose {
[super applyLayoutAttributes:pose];
if (!self.backgroundView) {
self.backgroundView = [[UIView alloc] init];
}
self.backgroundView.backgroundColor = pose.backgroundColor;
}
@end
UICollectionViewFlowLayout
subclass
Now you need to make a subclass of UICollectionViewFlowLayout
that uses MyLayoutAttributes
instead of UICollectionViewLayoutAttributes
, and sets the backgroundColor
of each MyLayoutAttributes
correctly. Let's define the interface to have a property which is the array of colors to assign to rows:
@interface MyLayout : UICollectionViewFlowLayout
@property (nonatomic, copy) NSArray *rowColors;
@end
The first thing we need to do in our implementation is specify what layout attributes class we want it to use:
@implementation MyLayout
+ (Class)layoutAttributesClass {
return [MyLayoutAttributes class];
}
Next, we need to override two methods of UICollectionViewLayout
to set the backgroundColor
property of each pose. We call on super
to get the set of poses, and then use a helper method to set the background colors:
- (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;
}
Here's the method that actually assigns the background colors:
- (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];
}
}
Note that this method makes several assumptions:
- It assumes the scroll direction is vertical.
- It assumes all items are the same size.
- It assumes all sections have the same insets and line spacings.
- It assumes every section has at least one item.
The reason for the last assumption is that all rows in a section are followed by the minimum line spacing, except for the last row, which is followed by the bottom section inset. I need to know how many rows preceded the current item's row. I try to do that by dividing the Y coordinate by the height of a row… but the last row of each section is shorter than the others. Hence the fudging.
Applying Your New Classes
Anyway, now we need to put these new classes to use.
First, we need to use MyLayout
instead of UICollectionViewFlowLayout
. If you're setting up your collection view in code, just create an instead of MyLayout
and assign it to the collection view. If you're setting things up in a storyboard, find the collection view's layout (it is in the storyboard outliner as a child of the collection view) and set its custom class to MyLayout
.
Second, we need to assign an array of colors to the layout. If you're using a storyboard, you probably want to do this in viewDidLoad
. You could ask the collection view for its layout and then cast it to MyLayout
. I prefer to use an outlet of the proper type, connected to the layout object in the storyboard.
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.layout.rowColors = @[
[UIColor lightGrayColor],
[UIColor cyanColor],
];
}
Result
If you got everything set up correctly, you'll get a result like this:
and in landscape orientation it looks like this:
I've put my test project in this github repository.
这篇关于如何根据行替换 UICollectiveViewCell 的背景颜色?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!