我知道这对UITableViewCells来说相当容易,但我不知道如何使用UICollectionView来解决这个问题。
EDIT。图片澄清。单元格的文本内容在这里不一样,但它们应该是。 在风景中:
纵向:
我尝试根据cellForItemAtIndexPath:
方法中索引路径的row属性,天真地将单元格文本标签的颜色切换为单元格的背景颜色。但是,Index Path的row属性实际上不是UICollectionViewFlowLayout中的一行。
答案 0 :(得分:9)
集合视图及其布局都不会告诉您项目的“行号”。你必须自己计算它。
如果您的所有测量结果都是一致的(如果您没有实施任何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
的{{1}}子类,并正确设置每个UICollectionViewLayoutAttributes
的{{1}}。让我们定义接口,使其具有一个属性,该属性是要分配给行的颜色数组:
backgroundColor
我们在实现中需要做的第一件事是指定我们希望它使用的布局属性类:
MyLayoutAttributes
接下来,我们需要覆盖@interface MyLayout : UICollectionViewFlowLayout
@property (nonatomic, copy) NSArray *rowColors;
@end
的两个方法来设置每个姿势的@implementation MyLayout
+ (Class)layoutAttributesClass {
return [MyLayoutAttributes class];
}
属性。我们调用UICollectionViewLayout
获取姿势集,然后使用辅助方法设置背景颜色:
backgroundColor
这是实际分配背景颜色的方法:
super
请注意,此方法有几个假设:
最后一个假设的原因是一个部分中的所有行后跟最小行间距,除之外的最后一行,后面是底部插入。我需要知道当前项的行前面有多少行。我尝试通过将Y坐标除以行的高度来做到这一点......但每个部分的最后一行比其他部分短。因此捏造。
无论如何,现在我们需要使用这些新类。
首先,我们需要使用- (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];
}
}
。如果您要在代码中设置集合视图,只需创建一个而不是MyLayout
并将其分配给集合视图。如果您在故事板中进行设置,请查找集合视图的布局(它在故事板大纲中作为集合视图的子级)并将其自定义类设置为UICollectionViewFlowLayout
。
其次,我们需要为布局指定一组颜色。如果您使用的是故事板,则可能需要在MyLayout
中执行此操作。您可以询问集合视图的布局,然后将其转换为MyLayout
。我更喜欢使用正确类型的插座,连接到故事板中的布局对象。
viewDidLoad
如果你正确设置了所有内容,你会得到如下结果:
并且在横向方向上它看起来像这样:
我已将测试项目in this github repository。
答案 1 :(得分:1)
我认为没有子流程布局可以有任何好的通用方法。对于更具体的情况,您可以使用整数数学与模数运算符组合来从indexPath获取“行”。因此,如果每行有5个项目,则可以从此表达式返回0或1:
NSInteger rowTest = (indexPath.row / 5) % 2;
只需测试此值,然后相应地更改颜色。当然,您必须在旋转时更改表达式,因为每行上都有不同数量的项目。
答案 2 :(得分:0)
使用indexPath.section属性获取一行。
答案 3 :(得分:0)
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
<UICollectionViewDelegate,UICollectionViewDataSource,UICollectionViewDelegateFlowLayout>
@end
#import "ViewController.h"
#define WIDTH 200
#define HEIGHT 200
#define XMARGIN 50
#define YMARGIN 20
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UICollectionView *collectionView;
@property (assign, nonatomic) int numberOfCols;
@end
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
UINib* cellNib = [UINib nibWithNibName:@"CollectionCell" bundle:nil];
[self.collectionView registerNib:cellNib forCellWithReuseIdentifier:@"CollectionCell"];
}
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
return 1;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return 6;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"CollectionCell" forIndexPath:indexPath];
NSLog(@"Row number %d",indexPath.row);
int rem = (indexPath.row / self.numberOfCols);
NSLog(@"col number %d", rem);
if ( rem % 2 == 0 )
cell.backgroundColor = [UIColor yellowColor];
else
cell.backgroundColor = [UIColor greenColor];
return cell;
}
#pragma mark – UICollectionViewDelegateFlowLayout
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
self.numberOfCols = (collectionView.frame.size.width - (XMARGIN*2)) / (WIDTH);
NSLog(@"Number of cols is %d",self.numberOfCols);
return CGSizeMake(WIDTH,HEIGHT);
}
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section
{
return UIEdgeInsetsMake(XMARGIN, YMARGIN, XMARGIN, YMARGIN);
}
- (void) didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
[self.collectionView reloadData];
}
答案 4 :(得分:0)
这很令人讨厌,如果有一个标题会受到破坏,但至少这会让你前进。在cellForItemAtIndexPath中......
// dequeue cell
CGFloat originY = cell.frame.origin.y;
// if there are headers, then grab the header view and...
originY -= header.bounds.size.height * indexPath.section;
NSInteger row = originY / cell.bounds.size.height;
BOOL evenRow = row%2 == 0;