如何确定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,则在项目之间仍可能会看到几个像素。 如果你想更多地控制项目的间隔,你应该使用不同的布局(可能是你自己创建的)。

  • 链接地址: http://www.djcxy.com/p/84155.html

    上一篇: How do you determine spacing between cells in UICollectionView flowLayout

    下一篇: Memory leak when using Image.Save(Stream, ImageFormat)