Skip to content

Commit fd02180

Browse files
committed
Centered!
0 parents  commit fd02180

File tree

38 files changed

+2060
-0
lines changed

38 files changed

+2060
-0
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
**/xcuserdata/**
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
version = "1.0.0"
2+
3+
Pod::Spec.new do |s|
4+
s.name = 'CollectionViewCenteredFlowLayout'
5+
s.version = version
6+
s.summary = 'A layout for UICollectionView that aligns the cells to the center'
7+
s.description = <<-DESC
8+
A `UICollectionViewLayout` implementation that aligns the cells to the center.
9+
10+
It uses `UICollectionViewFlowLayout` under the hood.
11+
DESC
12+
s.homepage = 'https://github.com/coeur/CollectionViewCenteredFlowLayout'
13+
s.screenshots = 'https://raw.githubusercontent.com/coeur/CollectionViewCenteredFlowLayout/master/screenshot.png'
14+
s.license = { :type => "MIT", :file => "LICENSE" }
15+
s.authors = { 'Antoine Cœur' => '' }
16+
s.social_media_url = 'http://twitter.com/adigitalknight'
17+
s.platform = :ios, '8.0'
18+
s.source = { :git => 'https://github.com/coeur/CollectionViewCenteredFlowLayout.git', :tag => version }
19+
s.source_files = 'CollectionViewCenteredFlowLayout/*.swift'
20+
end
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
2+
// Copyright (c) 2017 Cœur
3+
//
4+
// Permission is hereby granted, free of charge, to any person obtaining a copy of
5+
// this software and associated documentation files (the "Software"), to deal in
6+
// the Software without restriction, including without limitation the rights to
7+
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
8+
// the Software, and to permit persons to whom the Software is furnished to do so,
9+
// subject to the following conditions:
10+
//
11+
// The above copyright notice and this permission notice shall be included in all
12+
// copies or substantial portions of the Software.
13+
//
14+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
16+
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
17+
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
18+
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19+
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20+
21+
import UIKit
22+
23+
/**
24+
* Simple UICollectionViewFlowLayout that centers the cells rather than justify them
25+
*
26+
* Based on https://github.com/Coeur/UICollectionViewLeftAlignedLayout
27+
*/
28+
open class CollectionViewCenteredFlowLayout: UICollectionViewFlowLayout {
29+
open override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
30+
guard let layoutAttributesForElements = super.layoutAttributesForElements(in: rect) else {
31+
return nil
32+
}
33+
guard let collectionView = collectionView else {
34+
return layoutAttributesForElements
35+
}
36+
// we group copies of the elements from the same row/column
37+
var representedElements: [UICollectionViewLayoutAttributes] = []
38+
var cells: [[UICollectionViewLayoutAttributes]] = [[]]
39+
var previousFrame: CGRect? = nil
40+
for layoutAttributes in layoutAttributesForElements {
41+
guard layoutAttributes.representedElementKind == nil else {
42+
representedElements.append(layoutAttributes)
43+
continue
44+
}
45+
let currentItemAttributes = layoutAttributes.copy() as! UICollectionViewLayoutAttributes
46+
if previousFrame != nil {
47+
if scrollDirection == .vertical {
48+
// if the current frame, once stretched to the full row intersects the previous frame then they are on the same row
49+
if !currentItemAttributes.frame.intersects(CGRect(x: -.infinity, y: previousFrame!.origin.y, width: .infinity, height: previousFrame!.size.height)) {
50+
// the item is on a different row
51+
cells.append([])
52+
}
53+
} else {
54+
// if the current frame, once stretched to the full column intersects the previous frame then they are on the same column
55+
if !currentItemAttributes.frame.intersects(CGRect(x: previousFrame!.origin.x, y: -.infinity, width: previousFrame!.size.width, height: .infinity)) {
56+
// the item is on a different column
57+
cells.append([])
58+
}
59+
}
60+
}
61+
cells[cells.endIndex - 1].append(currentItemAttributes)
62+
previousFrame = currentItemAttributes.frame
63+
}
64+
return representedElements + cells.flatMap { group -> [UICollectionViewLayoutAttributes] in
65+
guard !group.isEmpty else {
66+
return group
67+
}
68+
let section = group.first!.indexPath.section
69+
let evaluatedSectionInset = (collectionView.delegate as? UICollectionViewDelegateFlowLayout)?.collectionView?(collectionView, layout: self, insetForSectionAt: section) ?? sectionInset
70+
let evaluatedMinimumInteritemSpacing = (collectionView.delegate as? UICollectionViewDelegateFlowLayout)?.collectionView?(collectionView, layout: self, minimumInteritemSpacingForSectionAt: section) ?? minimumInteritemSpacing
71+
if scrollDirection == .vertical {
72+
var origin = (collectionView.bounds.width + evaluatedSectionInset.left - evaluatedSectionInset.right - group.reduce(0, { $0 + $1.frame.size.width }) - CGFloat(group.count - 1) * evaluatedMinimumInteritemSpacing) / 2
73+
return group.map {
74+
$0.frame.origin.x = origin
75+
origin += $0.frame.size.width + evaluatedMinimumInteritemSpacing
76+
return $0
77+
}
78+
} else {
79+
var origin = (collectionView.bounds.height + evaluatedSectionInset.top - evaluatedSectionInset.bottom - group.reduce(0, { $0 + $1.frame.size.height }) - CGFloat(group.count - 1) * evaluatedMinimumInteritemSpacing) / 2
80+
return group.map {
81+
$0.frame.origin.y = origin
82+
origin += $0.frame.size.height + evaluatedMinimumInteritemSpacing
83+
return $0
84+
}
85+
}
86+
}
87+
}
88+
}

0 commit comments

Comments
 (0)