UICollectionView中的单元格间距

如何在UICollectionView的部分中设置单元格间距?我知道有一个属性minimumInteritemSpacing,我已经将它设置为5.0,但间距仍然没有出现5.0。我已经实现了flowout委托方法。

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


return 5.0;
}

我仍然没有得到想要的结果。我认为这是最小间距。有没有什么方法可以设置最大间距?

simulator sc

314073 次浏览

试试这个方法:

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


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


return insets;
}

请注意属性名minimumInterItemSpacing。这将是不准确项之间的< >强最小间距空格。如果你设置minimumInterItemSpacing为某个值,你可以确保spacing不会小于该值。但有机会获得更高的价值。

实际上,项之间的间距取决于几个因素itemSizesectionInset。集合视图根据这些值动态放置内容。所以你不能保证精确的间距。你应该用sectionInsetminimumInterItemSpacing做一些试错。

在头文件中定义UICollectionViewDelegateFlowLayout协议。

实现如下UICollectionViewDelegateFlowLayout协议的方法:

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

点击这里查看苹果文档的UIEdgeInsetMake方法。

支持第一个问题。我试图在UICollectionView上将间距设置为5px,但这行不通,同样适用于UIEdgeInsetsMake(0,0,0,0)

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

enter image description here

这是我的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;
}

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

enter image description here

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

我知道这个话题很老了,但如果有人还需要正确答案,你需要什么:

  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;
    }
    

where maximumSpacing could be set to any value you prefer. This trick guarantees that the space between cells would be EXACTLY equal to maximumSpacing!!

我使用monotouch,所以名称和代码会有点不同,但你可以通过确保集合视图的宽度等于(x *单元格宽度)+ (x-1) * MinimumSpacing与x =每行单元格的数量来做到这一点。

只需要根据MinimumInteritemSpacing和Cell的宽度执行以下步骤

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)现在调整insets(在本例中,我们将其添加到右侧,因此集合视图的左侧位置保持不变

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

使用水平流布局,我也得到了10点之间的单元格间距。为了移除空格,我需要将minimumLineSpacingminimumInterItemSpacing设置为0。

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

此外,如果所有单元格大小相同,直接在流布局上设置属性比使用委托方法更简单、更有效。

试试下面的代码,确保每个项目之间的间距为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;
}

我偶然发现了一个与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的中心

斯威夫特版最流行的答案。单元格之间的空格将等于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
}
}

投票的答案(还有斯威夫特版本)有一个小问题:右边会有一个大的空格。

这是因为流布局是定制的,以使单元格间距精确,具有左浮动行为。

我的解决方案是操纵部分插入,使部分是对齐中心,但间距是完全指定的。

在下面的截图中,项目/行间距正好是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
}

记住,它是最小行间距,而不是最小项间间距或单元格空间。因为你的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
}

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

我尝试了iago849的答案,它起作用了,但后来我发现我甚至不需要他的答案。出于某种原因,设置minimumInterItemSpacing没有任何作用。我的项目/单元格之间的间距可以完全由minimumLineSpacing控制。

不知道为什么会这样,但确实有效。

以上解决方案 by 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
}
}

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

只需从storyboard/Xib文件中选择UICollectionView,然后按下图所示单击尺寸检查器

enter image description here

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

1)用于设置行间距。

[self.collectionView setMinimumLineSpacing:5];

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

[self.collectionView setMinimumInteritemSpacing:5];

回答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。所以我的解决方案在这里找到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
}

我有问题与接受的答案,所以我更新了它,这是为我工作:

. h

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

00

@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

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
}

我在Swift 3单元格间距的解决方案,如Instagram:

enter image description here

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 < / p >

如果你想在不影响实际单元格大小的情况下调整间距,这是最适合我的解决方案。#xcode 9 #tvOS11 #iOS11 < em > #迅速< / em >

所以在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
}

间距的简单代码

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

我尝试了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 < / p >

故事板的方法

在你的故事板中选择CollectionView,然后进入尺寸检查器,设置单元格和行的最小间距为5

 ></a></p>


<h2>Swift 5编程方式</h2>


<pre><code>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)
}()
</code></pre></div>
                                                                            </div>
                                </div>
                            </div>
                        </div>
                                                <div class=

如果你正在创建一个水平集合视图,那么为了在单元格之间留出空间,你需要设置属性minimumLineSpacing

Swift 5 UIKit编程

 //Create UICollectionView
lazy var collectionView: UICollectionView = {
    

let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
    

//CollectionCellView width autoSize
layout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize
    

let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
collectionView.translatesAutoresizingMaskIntoConstraints = false
    

collectionView.register(CustomCollectionViewCell.self, forCellWithReuseIdentifier: cellId)
collectionView.backgroundColor = .clear
collectionView.delegate = self
collectionView.dataSource = self
collectionView.alwaysBounceHorizontal = true


//Add Spacing in each cell
layout.minimumInteritemSpacing = 15
layout.minimumLineSpacing = 15
    

return collectionView
}()