如何确定UICollectionView flowLayout中单元格之间的间距
我有一个流布局的UICollectionView,每个单元格是一个正方形。 我如何确定每行上每个单元格之间的间距? 我似乎无法找到适当的设置。 我看到nib文件中有一个用于集合视图的最小间距属性,但我将其设置为0,并且单元格甚至没有粘贴。
任何其他想法?
更新:这个答案的Swift版本:https://github.com/fanpyi/UICollectionViewLeftAlignedLayout-Swift
以@亚光为首,我修改了他的代码,以确保项目始终保持对齐。 我发现如果一个项目本身结束在一行上,它将以流布局为中心。 我做了以下更改以解决此问题。
这种情况只会发生在宽度不同的单元格时,这可能导致像下面这样的布局。 由于UICollectionViewFlowLayout
的行为,最后一行始终保持一致,问题在于它们本身在任何行中但最后一行中的项。
我看到@ matt的代码。
在这个例子中,我们看到如果单元格自己最终在单元格中,单元格就会居中。 下面的代码可以确保您的收藏视图看起来像这样。
#import "CWDLeftAlignedCollectionViewFlowLayout.h"
const NSInteger kMaxCellSpacing = 9;
@implementation CWDLeftAlignedCollectionViewFlowLayout
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {
NSArray* attributesToReturn = [super layoutAttributesForElementsInRect:rect];
for (UICollectionViewLayoutAttributes* attributes in attributesToReturn) {
if (nil == attributes.representedElementKind) {
NSIndexPath* indexPath = attributes.indexPath;
attributes.frame = [self layoutAttributesForItemAtIndexPath:indexPath].frame;
}
}
return attributesToReturn;
}
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath {
UICollectionViewLayoutAttributes* currentItemAttributes =
[super layoutAttributesForItemAtIndexPath:indexPath];
UIEdgeInsets sectionInset = [(UICollectionViewFlowLayout *)self.collectionView.collectionViewLayout sectionInset];
if (indexPath.item == 0) { // first item of section
CGRect frame = currentItemAttributes.frame;
frame.origin.x = sectionInset.left; // first item of the section should always be left aligned
currentItemAttributes.frame = frame;
return currentItemAttributes;
}
NSIndexPath* previousIndexPath = [NSIndexPath indexPathForItem:indexPath.item-1 inSection:indexPath.section];
CGRect previousFrame = [self layoutAttributesForItemAtIndexPath:previousIndexPath].frame;
CGFloat previousFrameRightPoint = previousFrame.origin.x + previousFrame.size.width + kMaxCellSpacing;
CGRect currentFrame = currentItemAttributes.frame;
CGRect strecthedCurrentFrame = CGRectMake(0,
currentFrame.origin.y,
self.collectionView.frame.size.width,
currentFrame.size.height);
if (!CGRectIntersectsRect(previousFrame, strecthedCurrentFrame)) { // if current item is the first item on the line
// the approach here is to take the current frame, left align it to the edge of the view
// then stretch it the width of the collection view, if it intersects with the previous frame then that means it
// is on the same line, otherwise it is on it's own new line
CGRect frame = currentItemAttributes.frame;
frame.origin.x = sectionInset.left; // first item on the line should always be left aligned
currentItemAttributes.frame = frame;
return currentItemAttributes;
}
CGRect frame = currentItemAttributes.frame;
frame.origin.x = previousFrameRightPoint;
currentItemAttributes.frame = frame;
return currentItemAttributes;
}
@end
为了获得最大的项目间距,子类UICollectionViewFlowLayout并重写layoutAttributesForElementsInRect:
和layoutAttributesForItemAtIndexPath:
例如,一个常见的问题是:集合视图的行是左对齐的,除了最后一行是左对齐的。 比方说,我们希望所有的线都是左对齐的,以便它们之间的距离是,比如说10点。 这是一个简单的方法(在你的UICollectionViewFlowLayout子类中):
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {
NSArray* arr = [super layoutAttributesForElementsInRect:rect];
for (UICollectionViewLayoutAttributes* atts in arr) {
if (nil == atts.representedElementKind) {
NSIndexPath* ip = atts.indexPath;
atts.frame = [self layoutAttributesForItemAtIndexPath:ip].frame;
}
}
return arr;
}
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath {
UICollectionViewLayoutAttributes* atts =
[super layoutAttributesForItemAtIndexPath:indexPath];
if (indexPath.item == 0) // degenerate case 1, first item of section
return atts;
NSIndexPath* ipPrev =
[NSIndexPath indexPathForItem:indexPath.item-1 inSection:indexPath.section];
CGRect fPrev = [self layoutAttributesForItemAtIndexPath:ipPrev].frame;
CGFloat rightPrev = fPrev.origin.x + fPrev.size.width + 10;
if (atts.frame.origin.x <= rightPrev) // degenerate case 2, first item of line
return atts;
CGRect f = atts.frame;
f.origin.x = rightPrev;
atts.frame = f;
return atts;
}
这很容易的原因是我们没有真正执行布局的繁重工作; 我们正在利用UICollectionViewFlowLayout已经为我们完成的布局工作。 它已经决定了每一行有多少项目; 如果你明白我的意思,我们只是在阅读这些文章并把它们放在一起。
有几件事情需要考虑:
尝试更改IB中的最小间距,但将光标留在该字段中。 请注意,Xcode不会立即将文档标记为已更改。 但是,当您点击不同的字段时,Xcode确实会注意到文档已更改,并在文件导航器中将其标记。 所以,请务必在进行更改后选中或点击其他字段。
进行更改后保存故事板/ xib文件,并确保重新构建应用程序。 不要错过这一步,然后你就会摸不清头脑,想知道为什么你的改变似乎没有任何效果。
UICollectionViewFlowLayout
具有minimumInteritemSpacing
属性,这是您在IB中设置的内容。 但集合的委托人也可以有一种方法来确定项目间间距。 该方法胜过布局的属性,所以如果你在委托中实现它,你的布局的属性将不会被使用。
请记住,间距有一个最小间距。 布局将使用该数字(无论它来自属性还是来自委托方法)作为最小允许空间,但如果它的剩余空间足够大,它可能会使用更大的空间。 因此,例如,如果将最小间距设置为0,则在项目之间仍可能会看到几个像素。 如果你想更多地控制项目的间隔,你应该使用不同的布局(可能是你自己创建的)。
上一篇: How do you determine spacing between cells in UICollectionView flowLayout