问题
I'm using a UICollectionView with only one section. Here's some visualization:
[ x x x ]
[ x x x ]
[ x x ]
If the last row in the UICollectionView does not have all 3 cells filled, I'd like to center those cells like so:
[ x x x ]
[ x x x ]
[ x x ]
I've tried to implement solutions from the following places:
How to center horizontally UICollectionView Cells?
How to center align the cells of a UICollectionView?
However, the solutions shifts all the cells, and I'd like to only shift the LAST row if that last row doesn't contain X number of cells since I only have one section.
I know how to set insets, but I don't know how to achieve this with being only one section and trying to adjust the inset on the last row of cells.
I just started using UICollectionView and not sure how to go around this issue?
回答1:
Sounds like you need everything a flow layout offers with a little customizations. Subclassing flow layout and overriding layoutAttributesForElements should do the job:
A quick and dirty implementation will basically ask FlowLayout to do the layout for a given rect, then figure out what items appear in the last row. If there are less than 3 items, then space them out evenly.
class LastRowCenteredLayout: UICollectionViewFlowLayout {
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
guard var elementAttributes = super.layoutAttributesForElements(in: rect) else { return nil }
guard elementAttributes.count > 0 else { return elementAttributes }
elementAttributes = elementAttributes.map { $0.copy() as! UICollectionViewLayoutAttributes }
let minY = elementAttributes.last!.frame.minY
let lastRowAttrs = elementAttributes.reversed().filter { $0.frame.minY == minY }
guard lastRowAttrs.count < 3,
let first = elementAttributes.first,
let last = elementAttributes.last else {
return elementAttributes
}
let horizontalPadding = rect.width - first.frame.minX - last.frame.maxX
let horizontalShift = horizontalPadding / 2.0
for attrs in lastRowAttrs {
attrs.frame = attrs.frame.offsetBy(dx: horizontalShift, dy: 0)
}
return elementAttributes
}
}
Note that if you plan on animating insertions/deletions, you should also override layoutAttributesForCellWithIndexPath: and ensure it returns consistent results.
Apple has a guide on FlowLayout with a section dedicated to subclassing.
Sample Playground:
https://gist.github.com/AnuragMishra/0a694dfa9be1a5eab9fc7368b69812ad
回答2:
The short answer is: you can't, using the provided UICollectionViewFlowLayout by Apple
The longer answer is: You're going to have to create a customer UICollectionViewLayout subclass and place the element yourself. Start by going through this tutorial. Then you should have a better understanding of the inner workings to be able to create your own custom layout.
回答3:
strong textyou can do this simple calculation in your collectionViewLayout function.
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
//return itemSize
let spaceBetweenCell :CGFloat = 0
let screenWidth = UIScreen.main.bounds.size.width - CGFloat(2 * spaceBetweenCell)
let totalSpace = spaceBetweenCell * 1.0
if indexPath.row == categories.count-1 {
// check if last cell is odd
if categories.count % 2 == 1 {
return CGSize(width: screenWidth , height: (screenWidth-totalSpace)/4) // all Width and same previous height
}else {
return itemSize
}
}else{
return itemSize
}
}
来源:https://stackoverflow.com/questions/41091177/swift-3-how-to-center-horizontally-the-last-row-of-cells-in-a-uicollectionview