UICollectionView中的单元格间距
如何在UICollectionView
的一部分中设置单元格间距? 我知道有一个属性minimumInteritemSpacing
我已经把它设置为5.0仍然没有出现间距5.0。 我已经实现了stream出委托方法。
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section { return 5.0; }
我仍然没有得到理想的结果。 我认为它的最小间距。 有没有什么办法可以设置最大间距?
我知道这个话题是老的,但是如果有人仍然需要正确的答案,你需要什么:
- 覆盖标准stream布局。
-
添加像这样的实现:
- (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 !!
支持最初的问题。 我试图让UICollectionView
上的间距为5px,但这不工作,以及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
使用水平stream布局,我也获得了单元之间的10点间距。 要删除我需要设置minimumLineSpacing
以及minimumInterItemSpacing
为零所需的间距。
UICollectionViewFlowLayout *flow = [[UICollectionViewFlowLayout alloc] init]; flow.itemSize = CGSizeMake(cellWidth, cellHeight); flow.scrollDirection = UICollectionViewScrollDirectionHorizontal; flow.minimumInteritemSpacing = 0; flow.minimumLineSpacing = 0;
另外,如果所有单元格的大小相同,则直接在stream布局上设置属性(而不是使用委托方法)会更简单,更高效。
试试这个代码,以确保你有每个项目之间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; }
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 } }
请记住,这是最小的行间距,而不是最小的项目间距或单元格空间。 因为你的collectionView的滚动方向是水平的 。
如果是垂直的,则需要为单元格之间的水平空间和单元格之间的垂直空间的行间距设置单元格空间或项目间空间。
Objective-C版本
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section { return 20; }
Swift版本:
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat { return 20 }
请注意属性名称minimumInterItemSpacing 。 这将是项目之间的最小间距 不是确切的间距。 如果将minimumInterItemSpacing设置为某个值,则可以确保间距不会小于该值。 但有机会获得更高的价值。
实际上项目之间的间距取决于几个因素itemSize和sectionInset 。 集合视图根据这些值dynamic地放置内容。 所以你不能保证确切的间距。 你应该用sectionInset和minimumInterItemSpacing做一些试验和错误。
我发现使用IB很容易configuration单元格或行之间的间距。
只需从storyboard / Xib文件中selectUICollectionView,然后单击Size Inspector ,如下图所示。
要以编程方式configuration空间,请使用以下属性。
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 } }
在头文件中定义UICollectionViewDelegateFlowLayout
协议。
执行如下的UICollectionViewDelegateFlowLayout
协议的以下方法:
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section { return UIEdgeInsetsMake(5, 5, 5, 5); }
点击这里查看UIEdgeInsetMake
方法的Apple文档。
答案 (也是迅捷版 )有一个小问题:右边会有一个很大的空白。
这是因为stream布局是自定义的,使单元格间距精确, 浮动左行为。
我的解决scheme是操纵部分embedded,以便该部分alignment中心,但间距是完全按照指定。
在下面的截图中,项目/行间距正好是8pt,而左右插入部分将大于8pt(使其居中alignment):
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 }
我使用monotouch,所以名称和代码将有所不同,但你可以通过确保collectionview的宽度等于(x *单元格宽度)+(x-1)* MinimumSpacing与x =数量每行的单元格。
只需根据您的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;
我偶然发现了一个与OP类似的问题。 不幸的是,接受的答案没有为我工作,因为collectionView
的内容不会居中。 因此,我想出了一个不同的解决scheme,它只需要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
vojtech-vrbka的上述解决scheme是正确的,但会触发警告:
警告:UICollectionViewFlowLayoutcaching的索引path的帧不匹配 – caching值:这可能是因为stream布局子类布局是修改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 } }
Swift 3版本
只需创build一个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 }
尝试玩这个方法:
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section { UIEdgeInsets insets = UIEdgeInsetsMake(?, ?, ?, ?); return insets; }
我有一个水平的UICollectionView
和子类UICollectionViewFlowLayout
。 集合视图具有较大的单元格,并且一次仅显示一行,集合视图适合屏幕的宽度。
我试过iago849的答案,它的工作,但后来我发现我甚至不需要他的答案。 出于某种原因,设置minimumInterItemSpacing
什么也不做。 我的项目/单元格之间的间距可以完全由minimumLineSpacing
控制。
不知道为什么这种方式,但它的作品。
以前的版本没有真正与部分> 1。所以我的解决scheme在这里findhttps://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
.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
我在Instagram的Swift 3
单元格行间距的解决scheme:
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) } }
如何检测设备programmaticlly: https : //stackoverflow.com/a/26962452/6013170