UICollectionView中的单元格间距


197

如何在的一部分中设置像元间距UICollectionView?我知道有一个属性minimumInteritemSpacing我将其设置为5.0,但间距未显示为5.0。我已经实现了流程委托方法。

- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section
{

    return 5.0;
}

我仍然没有得到理想的结果。我认为是最小间距。我没有办法设置最大间距吗?

模拟器sc


您是否检查是否正在输入委托方法。通过放置断点..
Prashant Nikam

是的,它正在进入代表,在IB中,我还将最小单元格间距设置为5。但是我不认为最小空间是对我有帮助的属性,因为它将确保每个单元格之间的最小间距应为5,但是如果collection视图有额外的空间,那么它将使用该额外的空间。应该有一些像最大的像元间距
Vishal Singh 2013年

我也有同样的问题。5px似乎不起作用。显然,我可以使用UITableView来执行此操作,但不能使用UICollectionView ...
jerik

我已经修正了一些计算方法。.i我会把它发布到明天。:)
Vishal Singh

注意2016年就这么简单: stackoverflow.com/a/28327193/294884
Fattie

Answers:


145

我知道这个话题很古老,但是如果有人仍然需要正确的答案,这里您需要什么:

  1. 覆盖标准流程布局。
  2. 像这样添加实现:

    - (NSArray *) layoutAttributesForElementsInRect:(CGRect)rect {
        NSArray *answer = [super layoutAttributesForElementsInRect:rect];
    
        for(int i = 1; i < [answer count]; ++i) {
            UICollectionViewLayoutAttributes *currentLayoutAttributes = answer[i];
            UICollectionViewLayoutAttributes *prevLayoutAttributes = answer[i - 1];
            NSInteger maximumSpacing = 4;
            NSInteger origin = CGRectGetMaxX(prevLayoutAttributes.frame);
    
            if(origin + maximumSpacing + currentLayoutAttributes.frame.size.width < self.collectionViewContentSize.width) {
                CGRect frame = currentLayoutAttributes.frame;
                frame.origin.x = origin + maximumSpacing;
                currentLayoutAttributes.frame = frame;
            }
        }
        return answer;
    }

其中,maximumSpacing可以设置为您喜欢的任何值。这个技巧保证了单元格之间的空间将完全等于maximumSpacing!


那么,我们该放在哪里?
强尼

1
嗨,乔尼,继承自标准Flow Layout,只需将此方法复制并粘贴到您的类中即可。
iago849'2014-4-2

1
请注意,您无需使用mutableCopy:,您无需更改数组的内容,而是可以更改数组中的对象。
Brock Boland 2014年

5
也许我做错了,或者这个想法不能100%起作用,因为当我滚动到最后时,我看到有些单元格彼此重叠了:(
pash3r

2
很棒的帖子。在某些情况下,我确实遇到了错误,导致布局的最后一行的格式不正确。为了解决我if将AND 更改为AND的附加条件: if(origin + maximumSpacing + currentLayoutAttributes.frame.size.width < self.collectionViewContentSize.width && currentLayoutAttributes.frame.origin.x > prevLayoutAttributes.frame.origin.x) {
chrisoneiota

190

支持最初的问题。我试图将间距设置为5px,UICollectionView但这不起作用,以及UIEdgeInsetsMake(0,0,0,0)...

在UITableView上,我可以通过直接在一行中指定x,y坐标来做到这一点...

在此处输入图片说明

这是我的UICollectionView代码:

#pragma mark collection view cell layout / size
- (CGSize)collectionView:(UICollectionView*)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
    return [self getCellSize:indexPath];  // will be w120xh100 or w190x100
    // if the width is higher, only one image will be shown in a line
}

#pragma mark collection view cell paddings
- (UIEdgeInsets)collectionView:(UICollectionView*)collectionView layout:(UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
    return UIEdgeInsetsMake(0, 0, 0, 0); // top, left, bottom, right
}

- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section {

    return 5.0;
}

更新:使用以下代码解决了我的问题。

在此处输入图片说明

ViewController.m

#import "ViewController.h"
#import "MagazineCell.h" // created just the default class. 

static NSString * const cellID = @"cellID";

@interface ViewController ()

@end

@implementation ViewController

#pragma mark - Collection view
-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
    return 1;
}
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
    return 30;
}

-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
    MagazineCell *mCell = (MagazineCell *)[collectionView dequeueReusableCellWithReuseIdentifier:cellID forIndexPath:indexPath];

    mCell.backgroundColor = [UIColor lightGrayColor];

    return mCell;
}

#pragma mark Collection view layout things
// Layout: Set cell size
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {

    NSLog(@"SETTING SIZE FOR ITEM AT INDEX %d", indexPath.row);
    CGSize mElementSize = CGSizeMake(104, 104);
    return mElementSize;
}
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section {
    return 2.0;
}

- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section {
    return 2.0;
}

// Layout: Set Edges
- (UIEdgeInsets)collectionView:
(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
   // return UIEdgeInsetsMake(0,8,0,8);  // top, left, bottom, right
    return UIEdgeInsetsMake(0,0,0,0);  // top, left, bottom, right
}

@end

这是一个更好的答案。看一下您可以在UICollectionViewDelegateFlowLayout中调整的回调,然后可以看到如何对其进行调整。
cynistersix 2014年

1
我认为这仅在项目+间距的宽度等于uicollectionview的宽度时才有效。
xi.lin

@JayprakashDubey目前我不适应这个问题。您必须尝试一下。祝你好运
jerik '16

您在哪里指定5px的单元格之间的宽度?
UKDataGeek '17

1
比接受的方法好得多的答案,主要是因为将UICollectionViewLayout子类化以仅重写一种方法似乎显得过大,并且鉴于需要重写的所有其他方法,这也不是小事。
Cindeselia'7

80

使用水平流布局,我还获得了单元格之间的10点间距。要删除我需要设置间距minimumLineSpacing以及minimumInterItemSpacing为零。

UICollectionViewFlowLayout *flow = [[UICollectionViewFlowLayout alloc] init];
flow.itemSize = CGSizeMake(cellWidth, cellHeight);
flow.scrollDirection = UICollectionViewScrollDirectionHorizontal;
flow.minimumInteritemSpacing = 0;
flow.minimumLineSpacing = 0;

另外,如果所有单元格的大小都相同,则直接在流布局上设置属性而不是使用委托方法会更简单有效。


34
令人惊讶的是,minimumLineSpacing影响了单元格之间的水平空间。
Matt H

4
我也是,我也需要水平滚动并在单元格之间设置零间距,并且minimumLineSpacing = 0是关键。
Wingzero

3
无需使用就能获得这种效果minimumInteritemSpacing。只需minimumLineSpacing = 0在我的水平布局上设置即可删除项目之间的水平间距。
Ziewvater

1
如果考虑一下,项目之间的水平距离就是水平流动布局的行间距。行距是典型的垂直流动布局中项目之间的垂直距离。
lancejabr

62

请记住,这是最小的行间距,而不是最小的项目间间距或单元格间距。因为您的collectionView的滚动方向是水平

如果它是垂直的,则需要为单元格之间的水平空间设置单元格空间或项目间空间,并为单元格之间的垂直空间设置行间距。

Objective-C版本

- (CGFloat)collectionView:(UICollectionView *)collectionView
                       layout:(UICollectionViewLayout*)collectionViewLayout
    minimumLineSpacingForSectionAtIndex:(NSInteger)section
    {
        return 20;
    }

迅捷版:

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
    return 20
}

现在,当我返回0时,底部空间消失了;如何清除右侧空间?
班加罗尔

嘿,我不太了解您的问题。但是我认为insetForSectionAtIndex是您想要的。-(UIEdgeInsets)collectionView:(UICollectionView *)collectionView布局:(UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {return UIEdgeInsetsMake(5,10,5,10); }
Vincent Joy 2015年

这是水平和垂直方向的最小行距。
斯瓦蒂

你救了我的日子(是)。
Umair_UAS '19

哦,我的话!我真不敢相信 谢谢
Magoo

36

尝试使用以下代码,以确保每个项目之间的间距为5px:

- (UIEdgeInsets)collectionView:(UICollectionView *) collectionView 
                        layout:(UICollectionViewLayout *) collectionViewLayout 
        insetForSectionAtIndex:(NSInteger) section {

    return UIEdgeInsetsMake(0, 0, 0, 5); // top, left, bottom, right
}

- (CGFloat)collectionView:(UICollectionView *) collectionView
                   layout:(UICollectionViewLayout *) collectionViewLayout
  minimumInteritemSpacingForSectionAtIndex:(NSInteger) section {    
    return 5.0;
}

请将您的代码格式化为代码块,以便在SO上很好地显示。
导管2014年

33

Swift版本最受欢迎的答案。单元格之间的空间将等于cellSpacing

class CustomViewFlowLayout : UICollectionViewFlowLayout {

    let cellSpacing:CGFloat = 4

    override func layoutAttributesForElementsInRect(rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        if let attributes = super.layoutAttributesForElementsInRect(rect) {
        for (index, attribute) in attributes.enumerate() {
                if index == 0 { continue }
                let prevLayoutAttributes = attributes[index - 1]
                let origin = CGRectGetMaxX(prevLayoutAttributes.frame)
                if(origin + cellSpacing + attribute.frame.size.width < self.collectionViewContentSize().width) {
                    attribute.frame.origin.x = origin + cellSpacing
                }
            }
            return attributes
        }
        return nil
    }
}

super.layoutAttributesForElements(in:rect)返回nil有什么想法吗?
Ashok R

与使用此方法的所有其他方法一样,此方法不适用于多行。即使在适当的委托方法和属性设置为使用0的情况下,行之间仍将出现间歇性的舍入错误样式的间隙。这可能是UICollectionView呈现问题。
Womble

30

我发现使用IB配置单元格或行之间的间距的简单方法。

只需从情节提要/ Xib文件中选择UICollectionView,然后单击“ 大小检查器 ”,如下图所示。

在此处输入图片说明

要以编程方式配置空间,请使用以下属性。

1)用于在行之间设置空间。

[self.collectionView setMinimumLineSpacing:5];

2)用于设置项目/单元格之间的空间。

[self.collectionView setMinimumInteritemSpacing:5];

1
那是最小空间,它将大于指定的值,而不总是大于指定的值。
Vishal Singh

21

请注意属性名称minimumInterItemSpacing。这将是项目之间的最小间距,而不是确切的间距。如果将minimumInterItemSpacing设置为某个值,则可以确保间距不会小于该值。但是有机会获得更高的价值。

实际上,项目之间的间距取决于几个因素itemSizesectionInset。集合视图根据这些值动态放置内容。因此,您不能保证确切的间距。您应该使用sectionInsetminimumInterItemSpacing进行一些试验和错误。


1
@阿尼尔边缘的昆虫?:D
NightFury 2014年

10
您的sectionInsects中可能存在错误。
Nestor 2014年

24
昆虫==错误&&昆虫!=插图:)
Nestor 2014年

16

Swift 3.0,Xcode 8的答案

1.确保设置了集合视图委托

class DashboardViewController: UIViewController {
    @IBOutlet weak var dashboardCollectionView: UICollectionView!

    override func viewDidLoad() {
        super.viewDidLoad()
        dashboardCollectionView.delegate = self
    }
}

2.实施UICollectionViewDelegateFlowLayout协议,而不是UICollectionViewDelegate。

extension DashboardViewController: UICollectionViewDelegateFlowLayout {
    fileprivate var sectionInsets: UIEdgeInsets {
        return .zero
    }

    fileprivate var itemsPerRow: CGFloat {
        return 2
    }

    fileprivate var interitemSpace: CGFloat {
        return 5.0
    }

    func collectionView(_ collectionView: UICollectionView,
                        layout collectionViewLayout: UICollectionViewLayout,
                        sizeForItemAt indexPath: IndexPath) -> CGSize {
        let sectionPadding = sectionInsets.left * (itemsPerRow + 1)
        let interitemPadding = max(0.0, itemsPerRow - 1) * interitemSpace
        let availableWidth = collectionView.bounds.width - sectionPadding - interitemPadding
        let widthPerItem = availableWidth / itemsPerRow

        return CGSize(width: widthPerItem, height: widthPerItem)
    }

    func collectionView(_ collectionView: UICollectionView,
                        layout collectionViewLayout: UICollectionViewLayout,
                        insetForSectionAt section: Int) -> UIEdgeInsets {
        return sectionInsets
    }

    func collectionView(_ collectionView: UICollectionView,
                        layout collectionViewLayout: UICollectionViewLayout,
                        minimumLineSpacingForSectionAt section: Int) -> CGFloat {
        return 0.0
    }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
        return interitemSpace
    }
}

1
认为您可以将公众撤离那里。应该工作正常,并且与所有其他功能一致。
爱德华·波特

这对垂直滚动收集视图有效吗?我有集合视图,在iPhone 6s和6s Plus之类的设备上它应该水平显示2个单元格,但对于比5s,5和SE更低的任何内容,应该只显示一个单元格。我当前的代码正在运行,但是在6s Plus设备中,单元之间的间隙太大且看起来很难看,我正在尝试缩小该间隙,这是唯一的要求,因为所有其他设备都按照我的设计工作。
AnBisw '17

11

间距简单代码

let layout = collectionView.collectionViewLayout as! UICollectionViewFlowLayout
layout.minimumInteritemSpacing = 10 // Some float value

3
对于水平像元间距,应使用:minimumLineSpacing
Alfi

9

投票的答案(以及迅速的版本)有一个小问题:会有右侧的大间距。

这是因为流布局是自定义的,以使单元间距精确,并且具有浮动特性。

我的解决方案是操纵剖面插图,使剖面位于中心对齐,但间距完全符合指定。

在下面的屏幕截图中,项目/行距正好为8pt,而左右插入部分将大于8pt(以使其居中对齐):

间隔均匀的细胞

这样的Swift代码:

private let minItemSpacing: CGFloat = 8
private let itemWidth: CGFloat      = 100
private let headerHeight: CGFloat   = 32

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()

    // Create our custom flow layout that evenly space out the items, and have them in the center
    let layout = UICollectionViewFlowLayout()
    layout.itemSize = CGSize(width: itemWidth, height: itemWidth)
    layout.minimumInteritemSpacing = minItemSpacing
    layout.minimumLineSpacing = minItemSpacing
    layout.headerReferenceSize = CGSize(width: 0, height: headerHeight)

    // Find n, where n is the number of item that can fit into the collection view
    var n: CGFloat = 1
    let containerWidth = collectionView.bounds.width
    while true {
        let nextN = n + 1
        let totalWidth = (nextN*itemWidth) + (nextN-1)*minItemSpacing
        if totalWidth > containerWidth {
            break
        } else {
            n = nextN
        }
    }

    // Calculate the section inset for left and right. 
    // Setting this section inset will manipulate the items such that they will all be aligned horizontally center.
    let inset = max(minItemSpacing, floor( (containerWidth - (n*itemWidth) - (n-1)*minItemSpacing) / 2 ) )
    layout.sectionInset = UIEdgeInsets(top: minItemSpacing, left: inset, bottom: minItemSpacing, right: inset)

    collectionView.collectionViewLayout = layout
}

1
我收到一个“ NSInvalidArgumentException”,原因:“ *** setObjectForKey:对象不能为零(键:<NSIndexPath:0xc000000000000016> {length = 2,path = 0-0})”未捕获的异常。
DaftWooly

...如果我没记错的话,您的while循环等效于: let n = Int((containerWidth + minItemSpacing)/((itemWidth+minItemSpacing)))
DaftWooly

没有按原样使用代码,但这为我为集合视图实现输出布局提供了最佳参考。欢呼声
Dima Gimburg

8

定义 UICollectionViewDelegateFlowLayout在头文件中协议。

UICollectionViewDelegateFlowLayout像这样实现以下协议方法:

- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section
{
    return UIEdgeInsetsMake(5, 5, 5, 5);
}

单击此处以查看UIEdgeInsetMake方法的Apple文档。


3

如果您想在不影响实际像元大小的情况下调整间距,这是最适合我的解决方案。#xcode 9#tvOS11#iOS11 #swift

因此,在UICollectionViewDelegateFlowLayout中,更改实现下一个方法,诀窍是您必须同时使用这两个方法,并且文档并没有真正让我思考这个方向。:D

open func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
    return cellSpacing
}

public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
    return cellSpacing
}

3

故事板方法

在情节提要中选择CollectionView,然后转到大小检查器,并将单元格和线条的最小间距设置为5

Swift 5以编程方式

lazy var collectionView: UICollectionView = {
        let layout = UICollectionViewFlowLayout()
        layout.scrollDirection = .horizontal

        //Provide Width and Height According to your need
        let width = UIScreen.main.bounds.width / 4
        let height = UIScreen.main.bounds.height / 10
        layout.itemSize = CGSize(width: width, height: height)

        //For Adjusting the cells spacing
        layout.minimumInteritemSpacing = 5
        layout.minimumLineSpacing = 5

        return UICollectionView(frame: self.view.frame, collectionViewLayout: layout)
    }()

2

我使用的是monotouch,因此名称和代码会有所不同,但是您可以通过确保collectionview的宽度等于(x *单元格宽度)+(x-1)* MinimumSpacing with x = amount来做到这一点。每行细胞数。

只需根据您的MinimumInteritemSpacing和单元格的宽度执行以下步骤

1)我们根据单元格大小+当前插图+最小间距来计算每行的项目数量

float currentTotalWidth = CollectionView.Frame.Width - Layout.SectionInset.Left - Layout.SectionInset.Right (Layout = flowlayout)
int amountOfCellsPerRow = (currentTotalWidth + MinimumSpacing) / (cell width + MinimumSpacing)

2)现在,您拥有所有信息来计算集合视图的预期宽度

float totalWidth =(amountOfCellsPerRow * cell width) + (amountOfCellsPerRow-1) * MinimumSpacing

3)因此,当前宽度与预期宽度之差为

float difference = currentTotalWidth - totalWidth;

4)现在调整插图(在此示例中,我们将其添加到右侧,因此collectionview的左侧位置保持不变

Layout.SectionInset.Right = Layout.SectionInset.Right + difference;

2

我有一个水平UICollectionView和子类UICollectionViewFlowLayout。集合视图具有大的单元格,一次仅显示一行,并且集合视图适合屏幕的宽度。

我尝试了iago849的答案,它奏效了,但是后来我发现我什至不需要他的答案。由于某种原因,设置minimumInterItemSpacing不会执行任何操作。我的项目/单元格之间的间距可以完全由minimumLineSpacing

不知道为什么它会这样工作,但是可以工作。


1
这似乎是正确的 -奇怪的是,“行”值实际上是水平布局情况下项目之间的分隔符。
Fattie

嘿@ user3344977-很高兴找到。我决定将这个问题分成一个单独的问题,直接解决水平滚动集合视图,以便对某些人更容易找到。我在那里参考你的答案。我的问题在这里:stackoverflow.com/q/61774415/826946
安迪·温斯坦

1

我偶然发现了与OP类似的问题。不幸的是,被接受的答案对我不起作用,因为该内容collectionView不会正确居中。因此,我想出了一个不同的解决方案,该解决方案仅要求中的所有项目collectionView都具有相同的宽度,这在问题中似乎是这样的:

#define cellSize 90

- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
    float width = collectionView.frame.size.width;
    float spacing = [self collectionView:collectionView layout:collectionViewLayout minimumInteritemSpacingForSectionAtIndex:section];
    int numberOfCells = (width + spacing) / (cellSize + spacing);
    int inset = (width + spacing - numberOfCells * (cellSize + spacing) ) / 2;

    return UIEdgeInsetsMake(0, inset, 0, inset);
}

该代码将确保返回的值...minimumInteritemSpacing...将是每个值之间的精确间隔,collectionViewCell并且还确保所有单元格一起位于中心。collectionView


太酷了。但是我想知道是否可以将类似的解决方案应用于元素之间的垂直间距
p0lAris

垂直间距,以防您水平滚动?
luk2302 2015年

1

上述溶液通过vojtech-vrbka是正确的,但它会触发一个警告:

警告:UICollectionViewFlowLayout缓存了索引路径的帧不匹配-缓存的值:这可能是由于流布局子类Layout是修改UICollectionViewFlowLayout返回的属性而不复制它们而发生的

以下代码可以解决此问题:

class CustomViewFlowLayout : UICollectionViewFlowLayout {

   let cellSpacing:CGFloat = 4

   override func layoutAttributesForElementsInRect(rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
       let original = super.layoutAttributesForElementsInRect(rect)

       if let original = original {
           let attributes = NSArray.init(array: original, copyItems: true) as! [UICollectionViewLayoutAttributes]

           for (index, attribute) in attributes.enumerate() {
                if index == 0 { continue }
                let prevLayoutAttributes = attributes[index - 1]
                let origin = CGRectGetMaxX(prevLayoutAttributes.frame)
                if(origin + cellSpacing + attribute.frame.size.width < self.collectionViewContentSize().width) {
                    attribute.frame.origin.x = origin + cellSpacing
                }
            }
            return attributes
       }
       return nil
   }
}

2
像使用这种方法的SO的其他答案一样,此方法确实适用于在collectionView的整个宽度上拟合单元格,但是行之间仍然存在间歇性的,可变高度的间隙。这可能是CollectionView实际呈现方式的限制。
Womble

1

Swift 3版本

只需创建UICollectionViewFlowLayout子类并粘贴此方法。

override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        guard let answer = super.layoutAttributesForElements(in: rect) else { return nil }

        for i in 1..<answer.count {
            let currentAttributes = answer[i]
            let previousAttributes = answer[i - 1]

            let maximumSpacing: CGFloat = 8
            let origin = previousAttributes.frame.maxX

            if (origin + maximumSpacing + currentAttributes.frame.size.width < self.collectionViewContentSize.width && currentAttributes.frame.origin.x > previousAttributes.frame.origin.x) {
                var frame = currentAttributes.frame
                frame.origin.x = origin + maximumSpacing
                currentAttributes.frame = frame
            }
        }

        return answer
}

这适用于水平拟合,但即使将minimumLineSpacingForSectionAt设置为返回0,并且layout.minimumLineSpacing设置为0,行之间仍将保留间隙。此外,由于第一个循环不在,collectionView中的触摸将使应用程序崩溃范围。
Womble

1

我已经尝试过iago849的答案,并且有效。

斯威夫特4

open override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
    guard let answer = super.layoutAttributesForElements(in: rect) else {
        return nil
    }
    let count = answer.count
    for i in 1..<count {
        let currentLayoutAttributes = answer[i]
        let prevLayoutAttributes = answer[i-1]
        let origin = prevLayoutAttributes.frame.maxX
        if (origin + CGFloat(spacing) + currentLayoutAttributes.frame.size.width) < self.collectionViewContentSize.width && currentLayoutAttributes.frame.origin.x > prevLayoutAttributes.frame.origin.x {
            var frame = currentLayoutAttributes.frame
            frame.origin.x = origin + CGFloat(spacing)
            currentLayoutAttributes.frame = frame
        }
    }
    return answer
}

这是github项目的链接。 https://github.com/vishalwaka/MultiTags


0

以前的版本实际上不适用于部分> 1 .。因此,我的解决方案位于https://codentrick.com/create-a-tag-flow-layout-with-uicollectionview/。对于懒惰的人:

override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
    let attributesForElementsInRect = super.layoutAttributesForElements(in: rect)
    var newAttributesForElementsInRect = [UICollectionViewLayoutAttributes]()
    // use a value to keep track of left margin
    var leftMargin: CGFloat = 0.0;
    for attributes in attributesForElementsInRect! {
        let refAttributes = attributes 
        // assign value if next row
        if (refAttributes.frame.origin.x == self.sectionInset.left) {
            leftMargin = self.sectionInset.left
        } else {
            // set x position of attributes to current margin
            var newLeftAlignedFrame = refAttributes.frame
            newLeftAlignedFrame.origin.x = leftMargin
            refAttributes.frame = newLeftAlignedFrame
        }
        // calculate new value for current margin
        leftMargin += refAttributes.frame.size.width + 10
        newAttributesForElementsInRect.append(refAttributes)
    }

    return newAttributesForElementsInRect
}

0

我对接受的答案有疑问,因此我对其进行了更新,这对我来说很有效:

。H

@interface MaxSpacingCollectionViewFlowLayout : UICollectionViewFlowLayout
@property (nonatomic,assign) CGFloat maxCellSpacing;
@end

.m

@implementation MaxSpacingCollectionViewFlowLayout

- (NSArray *) layoutAttributesForElementsInRect:(CGRect)rect {
    NSArray *attributes = [super layoutAttributesForElementsInRect:rect];

    if (attributes.count <= 0) return attributes;

    CGFloat firstCellOriginX = ((UICollectionViewLayoutAttributes *)attributes[0]).frame.origin.x;

    for(int i = 1; i < attributes.count; i++) {
        UICollectionViewLayoutAttributes *currentLayoutAttributes = attributes[i];
        if (currentLayoutAttributes.frame.origin.x == firstCellOriginX) { // The first cell of a new row
            continue;
        }

        UICollectionViewLayoutAttributes *prevLayoutAttributes = attributes[i - 1];
        CGFloat prevOriginMaxX = CGRectGetMaxX(prevLayoutAttributes.frame);
        if ((currentLayoutAttributes.frame.origin.x - prevOriginMaxX) > self.maxCellSpacing) {
            CGRect frame = currentLayoutAttributes.frame;
            frame.origin.x = prevOriginMaxX + self.maxCellSpacing;
            currentLayoutAttributes.frame = frame;
        }
    }
    return attributes;
}

@end

0

我在Swift 3像Instagram这样的单元格行距解决方案:

在此处输入图片说明

lazy var collectionView: UICollectionView = {
    let layout = UICollectionViewFlowLayout()
    let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
    cv.backgroundColor = UIColor.rgb(red: 227, green: 227, blue: 227)
    cv.showsVerticalScrollIndicator = false
    layout.scrollDirection = .vertical
    layout.minimumLineSpacing = 1
    layout.minimumInteritemSpacing = 1
    return cv
}()

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {

    switch UIDevice.current.modelName {
    case "iPhone 4":
        return CGSize(width: 106, height: 106)
    case "iPhone 5":
        return CGSize(width: 106, height: 106)
    case "iPhone 6,7":
        return CGSize(width: 124, height: 124)
    case "iPhone Plus":
        return CGSize(width: 137, height: 137)
    default:
        return CGSize(width: frame.width / 3, height: frame.width / 3)
    }
}

如何以编程方式检测设备:https : //stackoverflow.com/a/26962452/6013170


0

好吧,如果要创建水平集合视图,然后在单元格之间留出空间,则需要设置属性minimumLineSpacing


-1

尝试使用此方法:

- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView
                    layout:(UICollectionViewLayout*)collectionViewLayout
    insetForSectionAtIndex:(NSInteger)section {

    UIEdgeInsets insets = UIEdgeInsetsMake(?, ?, ?, ?);

    return insets;
}

2
这仅适用于部分之间的间距,不适用于单元格
Diego A. Rincon
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.