UICollectionView - 删除多余的间距
UICollectionView - Remove extra spacing
我有一个 iPad 应用程序,用于 UICollectionView
显示单元格网格。这些单元格具有完全相同的宽度但高度不同(因为有些单元格的文本比其他单元格多)。
我遇到的唯一问题是较短的单元格最终有额外的间距 above/below...这会造成 collection 视图不好看。它在不需要额外 space 的地方添加了额外的 space。我已经尝试将边缘插入设置为 0 并将最小行距设置为 0,但它仍然不起作用。
这是我的 collection 视图:
这是我想要的样子:
这是我的流程布局代码:
[self.infoList registerClass:[InfoCell class] forCellWithReuseIdentifier:@"InfoCell"];
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
[layout setItemSize:CGSizeMake(320, 160)];
[layout setScrollDirection:UICollectionViewScrollDirectionVertical];
[layout setMinimumInteritemSpacing:0];
[layout setMinimumLineSpacing:0];
[self.infoList setCollectionViewLayout:layout];
我也将边缘插入设置为 0:
-(UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
return UIEdgeInsetsZero;
}
如何删除多余的space?我发现唯一可行的方法是使所有单元格具有完全相同的高度,但这不是我想要的。有些单元格包含的文本比其他单元格多,所以我必须给它们额外的高度。
在我看来,您可以通过自定义 UICollectionViewLayout
来解决这个问题。你应该看看 Collection View Programming Guide for iOS.
使用下面的代码,我假设每行有 2 行列,项目具有相同的宽度和不同的高度。
const CGFloat kPadding = 5.f;
const NSUInteger kNumberSmallCellALine = 2;
@interface CustomCollectionViewLayout : UICollectionViewLayout
@property (nonatomic, strong) NSMutableArray *layoutAttributes;
@property (nonatomic, assign) CGFloat contentHeight;
@end
@implementation CustomCollectionViewLayout
// Use this method to perform the up-front calculations needed to provide layout information.
- (void)prepareLayout{
[super prepareLayout];
if (!self.layoutAttributes){
self.layoutAttributes = [[NSMutableArray alloc] init];
// Calculate width of each item
CGFloat cellWidth = (self.collectionView.frame.size.width - (kNumberSmallCellALine - 1) * kPadding) / kNumberSmallCellALine;
// Default height of contentSize
self.contentHeight = 0.f;
// Height of column items on the left
CGFloat leftColumnHeight = 0.f;
// Height of column items on the right
CGFloat rightColumnHeight = 0.f;
for (int i = 0 ; i < [self.collectionView numberOfItemsInSection:0] ; i ++){
// Height of item at index i
CGFloat height = i * 20 + 20;
CGFloat xPos, yPos = 0.f;
if (i % 2 == 0) {
// If item on the right
xPos = 0.f;
yPos = leftColumnHeight;
leftColumnHeight += height + kPadding;
} else {
// Item on the left
xPos = cellWidth + kPadding;
yPos = rightColumnHeight;
rightColumnHeight += height + kPadding;
}
// Update height of contentSize after adding new item
self.contentHeight = MAX(leftColumnHeight, rightColumnHeight);
UICollectionViewLayoutAttributes *attr = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:[NSIndexPath indexPathForRow:i inSection:0]];
attr.frame = CGRectMake(xPos,
yPos,
cellWidth,
height);
[self.layoutAttributes addObject:attr];
}
}
}
// Use this method to return the attributes for cells and views that are in the specified rectangle.
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect{
NSMutableArray *currentAttributes = [NSMutableArray new];
for (UICollectionViewLayoutAttributes *attr in self.layoutAttributes) {
if (CGRectIntersectsRect(attr.frame, rect))
{
[currentAttributes addObject:attr];
}
}
return currentAttributes;
}
// Use this method to return the overall size of the entire content area based on your initial calculations.
- (CGSize)collectionViewContentSize{
return CGSizeMake(self.collectionView.frame.size.width, self.contentHeight);
}
@end
正在使用
CustomCollectionViewLayout *layout = [[CustomCollectionViewLayout alloc] init];
[collectionView setCollectionViewLayout:layout];
这是一个解决您问题的演示。您应该更改每个项目的高度以适合您的情况。
更多信息和更容易理解,您可以查看My Demo Repo
注意 来自@Supertecnoboff
如果您支持多个设备方向(例如:iPad 应用),则必须重新加载 layoutAttributes 数据。否则旋转设备时布局将不正确。然后您需要在集合视图上调用 performBatchUpdates 以加载新的布局数据。
我相信你必须创建一个 custom layout。
本质上包括对以下方法的覆盖:
- - (void)prepareLayout;:执行需要的前期计算
提供布局信息。
- collectionViewContentSize: 总计return
整个内容区域的大小基于您的初始计算。
- layoutAttributesForElementsInRect:: return 单元格和视图的属性
在指定的矩形内。
prepareLayout
方法将有以下实现,这是一个粗略的实现,您可能需要根据需要进行调整。
- (void) prepareLayout {
if (self.cache.count == 0) {
UIEdgeInsets insets = self.collectionView.contentInset;
self.contentWidth = self.collectionView.bounds.size.width - (insets.left + insets.right);
CGFloat columnWidth = self.contentWidth / self.numberOfColumns;
NSMutableArray *xOffsets = [NSMutableArray new];
NSMutableArray *yOffsets = [NSMutableArray new];
for (int i = 0; i < self.numberOfColumns; i++) {
[xOffsets addObject: @(i * columnWidth)];
[yOffsets addObject: @(0)];
}
int column = 0;
for (int i = 0; i < [self.collectionView numberOfItemsInSection:0]; i++) {
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:0];
CGFloat cellHeight = arc4random_uniform(200);
CGFloat height = self.cellPadding * 2 + cellHeight;
CGRect frame = CGRectMake((CGFloat)[[xOffsets objectAtIndex:column] floatValue],
(CGFloat)[[yOffsets objectAtIndex:column] floatValue],
columnWidth,
height);
CGRect insetFrame = CGRectInset(frame, self.cellPadding, self.cellPadding);
UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
attributes.frame = insetFrame;
[self.cache addObject:attributes];
self.contentHeight = MAX(self.contentHeight, CGRectGetMaxY(frame));
[yOffsets replaceObjectAtIndex:column withObject:@([[yOffsets objectAtIndex:column]floatValue] + height)];
column = column < (self.numberOfColumns - 1) ? (column + 1) : 0;
}
}
}
找到自定义 class 的 gist。
我有一个 iPad 应用程序,用于 UICollectionView
显示单元格网格。这些单元格具有完全相同的宽度但高度不同(因为有些单元格的文本比其他单元格多)。
我遇到的唯一问题是较短的单元格最终有额外的间距 above/below...这会造成 collection 视图不好看。它在不需要额外 space 的地方添加了额外的 space。我已经尝试将边缘插入设置为 0 并将最小行距设置为 0,但它仍然不起作用。
这是我的 collection 视图:
这是我想要的样子:
这是我的流程布局代码:
[self.infoList registerClass:[InfoCell class] forCellWithReuseIdentifier:@"InfoCell"];
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
[layout setItemSize:CGSizeMake(320, 160)];
[layout setScrollDirection:UICollectionViewScrollDirectionVertical];
[layout setMinimumInteritemSpacing:0];
[layout setMinimumLineSpacing:0];
[self.infoList setCollectionViewLayout:layout];
我也将边缘插入设置为 0:
-(UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
return UIEdgeInsetsZero;
}
如何删除多余的space?我发现唯一可行的方法是使所有单元格具有完全相同的高度,但这不是我想要的。有些单元格包含的文本比其他单元格多,所以我必须给它们额外的高度。
在我看来,您可以通过自定义 UICollectionViewLayout
来解决这个问题。你应该看看 Collection View Programming Guide for iOS.
使用下面的代码,我假设每行有 2 行列,项目具有相同的宽度和不同的高度。
const CGFloat kPadding = 5.f;
const NSUInteger kNumberSmallCellALine = 2;
@interface CustomCollectionViewLayout : UICollectionViewLayout
@property (nonatomic, strong) NSMutableArray *layoutAttributes;
@property (nonatomic, assign) CGFloat contentHeight;
@end
@implementation CustomCollectionViewLayout
// Use this method to perform the up-front calculations needed to provide layout information.
- (void)prepareLayout{
[super prepareLayout];
if (!self.layoutAttributes){
self.layoutAttributes = [[NSMutableArray alloc] init];
// Calculate width of each item
CGFloat cellWidth = (self.collectionView.frame.size.width - (kNumberSmallCellALine - 1) * kPadding) / kNumberSmallCellALine;
// Default height of contentSize
self.contentHeight = 0.f;
// Height of column items on the left
CGFloat leftColumnHeight = 0.f;
// Height of column items on the right
CGFloat rightColumnHeight = 0.f;
for (int i = 0 ; i < [self.collectionView numberOfItemsInSection:0] ; i ++){
// Height of item at index i
CGFloat height = i * 20 + 20;
CGFloat xPos, yPos = 0.f;
if (i % 2 == 0) {
// If item on the right
xPos = 0.f;
yPos = leftColumnHeight;
leftColumnHeight += height + kPadding;
} else {
// Item on the left
xPos = cellWidth + kPadding;
yPos = rightColumnHeight;
rightColumnHeight += height + kPadding;
}
// Update height of contentSize after adding new item
self.contentHeight = MAX(leftColumnHeight, rightColumnHeight);
UICollectionViewLayoutAttributes *attr = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:[NSIndexPath indexPathForRow:i inSection:0]];
attr.frame = CGRectMake(xPos,
yPos,
cellWidth,
height);
[self.layoutAttributes addObject:attr];
}
}
}
// Use this method to return the attributes for cells and views that are in the specified rectangle.
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect{
NSMutableArray *currentAttributes = [NSMutableArray new];
for (UICollectionViewLayoutAttributes *attr in self.layoutAttributes) {
if (CGRectIntersectsRect(attr.frame, rect))
{
[currentAttributes addObject:attr];
}
}
return currentAttributes;
}
// Use this method to return the overall size of the entire content area based on your initial calculations.
- (CGSize)collectionViewContentSize{
return CGSizeMake(self.collectionView.frame.size.width, self.contentHeight);
}
@end
正在使用
CustomCollectionViewLayout *layout = [[CustomCollectionViewLayout alloc] init];
[collectionView setCollectionViewLayout:layout];
这是一个解决您问题的演示。您应该更改每个项目的高度以适合您的情况。
更多信息和更容易理解,您可以查看My Demo Repo
注意 来自@Supertecnoboff
如果您支持多个设备方向(例如:iPad 应用),则必须重新加载 layoutAttributes 数据。否则旋转设备时布局将不正确。然后您需要在集合视图上调用 performBatchUpdates 以加载新的布局数据。
我相信你必须创建一个 custom layout。
本质上包括对以下方法的覆盖:
- - (void)prepareLayout;:执行需要的前期计算 提供布局信息。
- collectionViewContentSize: 总计return 整个内容区域的大小基于您的初始计算。
- layoutAttributesForElementsInRect:: return 单元格和视图的属性 在指定的矩形内。
prepareLayout
方法将有以下实现,这是一个粗略的实现,您可能需要根据需要进行调整。
- (void) prepareLayout {
if (self.cache.count == 0) {
UIEdgeInsets insets = self.collectionView.contentInset;
self.contentWidth = self.collectionView.bounds.size.width - (insets.left + insets.right);
CGFloat columnWidth = self.contentWidth / self.numberOfColumns;
NSMutableArray *xOffsets = [NSMutableArray new];
NSMutableArray *yOffsets = [NSMutableArray new];
for (int i = 0; i < self.numberOfColumns; i++) {
[xOffsets addObject: @(i * columnWidth)];
[yOffsets addObject: @(0)];
}
int column = 0;
for (int i = 0; i < [self.collectionView numberOfItemsInSection:0]; i++) {
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:0];
CGFloat cellHeight = arc4random_uniform(200);
CGFloat height = self.cellPadding * 2 + cellHeight;
CGRect frame = CGRectMake((CGFloat)[[xOffsets objectAtIndex:column] floatValue],
(CGFloat)[[yOffsets objectAtIndex:column] floatValue],
columnWidth,
height);
CGRect insetFrame = CGRectInset(frame, self.cellPadding, self.cellPadding);
UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
attributes.frame = insetFrame;
[self.cache addObject:attributes];
self.contentHeight = MAX(self.contentHeight, CGRectGetMaxY(frame));
[yOffsets replaceObjectAtIndex:column withObject:@([[yOffsets objectAtIndex:column]floatValue] + height)];
column = column < (self.numberOfColumns - 1) ? (column + 1) : 0;
}
}
}
找到自定义 class 的 gist。