我怎样才能在UICollectionView中居中行?

我有一个随机细胞UICollectionView 。 有什么方法可以让我排成行吗?

这是默认情况下的样子:

 [ xxxxxx ] [ xxxxxx ] [ xx ] 

以下是所需的布局:

 [ xxxxx ] [ xxxxx ] [ xx ] 

首先有一点背景 – 一个UICollectionView和一个UICollectionViewLayout结合在一起,它决定了单元格被放置在视图中的方式。 这意味着集合视图是非常灵活的(你可以创build几乎所有的布局),但也意味着修改布局可能有点混乱。

创build一个全新的布局类是很复杂的,所以你需要尝试和修改默认的布局( UICollectionViewFlowLayout )来让你的中心alignment。 为了使它更简单,你可能想要避免inheritancestream布局本身。

这里有一种方法(它可能不是最好的方法,但是这是我能想到的第一种方法) – 将单元分成两部分,如下所示:

 [ xxxxx ] <-- Section 1 [ xxxxx ] <-- Section 1 [ xx ] <-- Section 2 

这应该相当简单,只要知道滚动视图的宽度以及每行可以放入的单元格的数量即可。

然后,使用collectionView:layout:insetForSectionAtIndex: delegate方法来设置第二部分的边距,使其看起来是垂直居中的。 一旦你完成了这一步,你只需要确保你重新计算适当的部门/插槽,所以纵向和横向都可以被支持。

这里有一个类似的问题 – 如何居中alignmentUICollectionView的单元格? – 这个插入的方法会有更多的细节,尽pipe它不是很想和你做同样的事情。

我必须做这样的事情,但需要在一节中的所有单元格。 将UICollectionViewFlowLayout扩展到中心单元非常简单。 我做了一个豆荚:

https://github.com/keighl/KTCenterFlowLayout

在这里输入图像说明

如果任何人有一个CollectionView有2列,如果项目数是奇数,最后一个项目应居中alignment。 然后用这个

DNLastItemCenteredLayout

 - (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect { NSArray *attributes = [super layoutAttributesForElementsInRect:rect]; for (UICollectionViewLayoutAttributes *attribute in attributes) { NSInteger itemCount = [self.collectionView.dataSource collectionView:self.collectionView numberOfItemsInSection:attribute.indexPath.section]; if (itemCount % 2 == 1 && attribute.indexPath.item == itemCount - 1) { CGRect originalFrame = attribute.frame; attribute.frame = CGRectMake(self.collectionView.bounds.size.width/2-originalFrame.size.width/2, originalFrame.origin.y, originalFrame.size.width, originalFrame.size.height); } } return attributes; } 

这可以通过一个(相对)简单的自定义布局来实现,从UICollectionViewFlowLayout子类UICollectionViewFlowLayout 。 这是Swift的一个例子:

 /** * A simple `UICollectionViewFlowLayout` subclass that would make sure the items are center-aligned in the collection view, when scrolling vertically. */ class UICollectionViewFlowCenterLayout: UICollectionViewFlowLayout { override func layoutAttributesForElementsInRect(rect: CGRect) -> [UICollectionViewLayoutAttributes]? { guard let suggestedAttributes = super.layoutAttributesForElementsInRect(rect) else { return nil } guard scrollDirection == .Vertical else { return suggestedAttributes } var newAttributes: [UICollectionViewLayoutAttributes] = [] /// We will collect items for each row in this array var currentRowAttributes: [UICollectionViewLayoutAttributes] = [] /// We will use this variable to detect new rows when iterating over items var yOffset:CGFloat = sectionInset.top for attributes in suggestedAttributes { /// If we happen to run into a new row... if attributes.frame.origin.y != yOffset { /* * Update layout of all items in the previous row and add them to the resulting array */ centerSingleRowWithItemsAttributes(&currentRowAttributes, rect: rect) newAttributes += currentRowAttributes /* * Reset the accumulated values for the new row */ currentRowAttributes = [] yOffset = attributes.frame.origin.y } currentRowAttributes += [attributes] } /* * Update the layout of the last row. */ centerSingleRowWithItemsAttributes(&currentRowAttributes, rect: rect) newAttributes += currentRowAttributes return newAttributes } /** Updates the attributes for items, so that they are center-aligned in the given rect. - parameter attributes: Attributes of the items - parameter rect: Bounding rect */ private func centerSingleRowWithItemsAttributes(inout attributes: [UICollectionViewLayoutAttributes], rect: CGRect) { guard let item = attributes.last else { return } let itemsCount = CGFloat(attributes.count) let sideInsets = rect.width - (item.frame.width * itemsCount) - (minimumInteritemSpacing * (itemsCount - 1)) var leftOffset = sideInsets / 2 for attribute in attributes { attribute.frame.origin.x = leftOffset leftOffset += attribute.frame.width + minimumInteritemSpacing } } } 

我已经子类UICollectionViewFlowLayout – 改变了我在这里find的左alignment集合视图的代码。

  1. 左alignment集合视图
  2. 将线arrays的属性分组
  3. 对于每一行:
    • 计算右侧的空间
    • 为行的每个属性添加一半的空间

看起来像这样:

 - (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect { NSArray *attributesForElementsInRect = [super layoutAttributesForElementsInRect:rect]; NSMutableArray *newAttributesForElementsInRect = [[NSMutableArray alloc] initWithCapacity:attributesForElementsInRect.count]; CGFloat leftMargin = self.sectionInset.left; NSMutableArray *lines = [NSMutableArray array]; NSMutableArray *currLine = [NSMutableArray array]; for (UICollectionViewLayoutAttributes *attributes in attributesForElementsInRect) { // Handle new line BOOL newLine = attributes.frame.origin.x <= leftMargin; if (newLine) { leftMargin = self.sectionInset.left; //will add outside loop currLine = [NSMutableArray arrayWithObject:attributes]; } else { [currLine addObject:attributes]; } if ([lines indexOfObject:currLine] == NSNotFound) { [lines addObject:currLine]; } // Align to the left CGRect newLeftAlignedFrame = attributes.frame; newLeftAlignedFrame.origin.x = leftMargin; attributes.frame = newLeftAlignedFrame; leftMargin += attributes.frame.size.width + self.minimumInteritemSpacing; [newAttributesForElementsInRect addObject:attributes]; } // Center left aligned lines for (NSArray *line in lines) { UICollectionViewLayoutAttributes *lastAttributes = line.lastObject; CGFloat space = CGRectGetWidth(self.collectionView.frame) - CGRectGetMaxX(lastAttributes.frame); for (UICollectionViewLayoutAttributes *attributes in line) { CGRect newFrame = attributes.frame; newFrame.origin.x = newFrame.origin.x + space / 2; attributes.frame = newFrame; } } return newAttributesForElementsInRect; } 

希望它可以帮助别人:)

只需链接这个stream程布局。 你可以alignment中心,左边,右边。

  // // CellAllignmentFlowLayout.swift // UICollectionView // // Created by rajeshkumar Lingavel on 8/11/15. // Copyright © 2015 rajeshkumar Lingavel. All rights reserved. // import UIKit enum SZAlignment:Int { case Center, left, Right } class CellAllignmentFlowLayout: UICollectionViewFlowLayout { var alignment:SZAlignment! var padding:CGFloat! override func layoutAttributesForElementsInRect(rect: CGRect) -> [UICollectionViewLayoutAttributes]? { // NSArray *allAttributesInRect = [super // layoutAttributesForElementsInRect:rect]; let allAttributesInRect:NSArray = super.layoutAttributesForElementsInRect(rect)! var changedAttributes:NSArray = NSArray() switch(alignment.rawValue){ case 0: changedAttributes = alignCenter(allAttributesInRect) case 1: changedAttributes = alignLeft(allAttributesInRect) case 2: changedAttributes = alignRight(allAttributesInRect) default: assertionFailure("No Direction") } return changedAttributes as? [UICollectionViewLayoutAttributes] } private func alignCenter(allAttributesInRect:NSArray) -> NSArray{ let numberOfSection:Int = (self.collectionView?.numberOfSections())! let redefiendArray = NSMutableArray() for i in 0 ..< numberOfSection { let thisSectionObjects = sectionObjects(allAttributesInRect, section: i) let totalLines = numberOfLines(thisSectionObjects, section: i) let lastrowObjects = lastRow(thisSectionObjects, numberOfRows: totalLines, section: i) let lastRowObjectsRow = setMiddleTheLastRow(lastrowObjects) let start = (thisSectionObjects.count - lastrowObjects.count) for j in start..<thisSectionObjects.count{ thisSectionObjects.replaceObjectAtIndex(j, withObject: lastRowObjectsRow.objectAtIndex(j - start)) } redefiendArray.addObjectsFromArray(thisSectionObjects as [AnyObject]) } return redefiendArray } private func alignLeft(allAttributesInRect:NSArray) -> NSArray{ return allAttributesInRect; } private func alignRight(allAttributesInRect:NSArray) -> NSArray{ return allAttributesInRect; } private func getTotalLenthOftheSection(section:Int,allAttributesInRect:NSArray) -> CGFloat{ var totalLength:CGFloat = 0.0 totalLength = totalLength + (CGFloat (((self.collectionView?.numberOfItemsInSection(section))! - 1)) * padding) for attributes in allAttributesInRect { if(attributes.indexPath.section == section){ totalLength = totalLength + attributes.frame.width } } return totalLength } private func numberOfLines(allAttributesInRect:NSArray,section:Int)-> Int{ var totalLines:Int = 0 for attributes in allAttributesInRect { if(attributes.indexPath.section == section){ if (attributes.frame.origin.x == self.sectionInset.left){ totalLines = totalLines + 1 } } } return totalLines } private func sectionObjects(allAttributesInRect:NSArray,section:Int) -> NSMutableArray{ let objects:NSMutableArray = NSMutableArray() for attributes in allAttributesInRect { if(attributes.indexPath.section == section){ objects.addObject(attributes) } } return objects } private func lastRow(allAttributesInRect:NSArray,numberOfRows:Int,section:Int) -> NSMutableArray{ var totalLines:Int = 0 let lastRowArrays:NSMutableArray = NSMutableArray() for attributes in allAttributesInRect { if(attributes.indexPath.section == section){ if (attributes.frame.origin.x == self.sectionInset.left){ totalLines = totalLines + 1 if(totalLines == numberOfRows){ lastRowArrays.addObject(attributes) } } else{ if(totalLines == numberOfRows){ lastRowArrays.addObject(attributes) } } } } return lastRowArrays } private func setMiddleTheLastRow(lastRowAttrs:NSMutableArray)->NSMutableArray{ let redefinedValues = NSMutableArray() let totalLengthOftheView = self.collectionView?.frame.width var totalLenthOftheCells:CGFloat = 0.0 totalLenthOftheCells = totalLenthOftheCells + (CGFloat (lastRowAttrs.count) - 1) * padding for attrs in lastRowAttrs{ totalLenthOftheCells = totalLenthOftheCells + attrs.frame.width } var initalValue = (totalLengthOftheView!/2) - (totalLenthOftheCells/2) for i in 0..<lastRowAttrs.count { let changeingAttribute:UICollectionViewLayoutAttributes = lastRowAttrs[i] as! UICollectionViewLayoutAttributes var frame = changeingAttribute.frame frame.origin.x = initalValue changeingAttribute.frame = frame redefinedValues.addObject(changeingAttribute) initalValue = initalValue + changeingAttribute.frame.width + padding } return redefinedValues; } } 

Swift 3.0版本的类:

 class UICollectionViewFlowCenterLayout: UICollectionViewFlowLayout { override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? { guard let suggestedAttributes = super.layoutAttributesForElements(in: rect) else { return nil } guard scrollDirection == .vertical else { return suggestedAttributes } var newAttributes: [UICollectionViewLayoutAttributes] = [] var currentRowAttributes: [UICollectionViewLayoutAttributes] = [] var yOffset:CGFloat = sectionInset.top for attributes in suggestedAttributes { if attributes.frame.origin.y != yOffset { centerSingleRowWithItemsAttributes(attributes: &currentRowAttributes, rect: rect) newAttributes += currentRowAttributes currentRowAttributes = [] yOffset = attributes.frame.origin.y } currentRowAttributes += [attributes] } centerSingleRowWithItemsAttributes(attributes: &currentRowAttributes, rect: rect) newAttributes += currentRowAttributes return newAttributes } private func centerSingleRowWithItemsAttributes( attributes: inout [UICollectionViewLayoutAttributes], rect: CGRect) { guard let item = attributes.last else { return } let itemsCount = CGFloat(attributes.count) let sideInsets = rect.width - (item.frame.width * itemsCount) - (minimumInteritemSpacing * (itemsCount - 1)) var leftOffset = sideInsets / 2 for attribute in attributes { attribute.frame.origin.x = leftOffset leftOffset += attribute.frame.width + minimumInteritemSpacing } } }