Skip to content

Commit a2454c4

Browse files
authored
Merge pull request #19 from giulio92/develop
SwiftLint support + overall project improvements
2 parents 2e28f25 + 9972d98 commit a2454c4

10 files changed

Lines changed: 117 additions & 67 deletions

File tree

.swiftlint.yml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# rule identifiers to exclude from running
2+
disabled_rules:
3+
- line_length
4+
5+
# some rules are only opt-in
6+
opt_in_rules:
7+
# Find all the available rules by running:
8+
# swiftlint rules
9+
10+
11+
# paths to include during linting. `--path` is ignored if present.
12+
included:
13+
14+
15+
# paths to ignore during linting. Takes precedence over `included`.
16+
excluded:
17+
18+
19+
# configurable rules can be customized from this configuration file
20+
# binary rules can set their severity level
21+
force_cast: warning

.travis.yml

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,4 @@ before_install:
1818
- xcodebuild -version
1919
- xcodebuild -showsdks
2020

21-
# This command will fix Travis CI duplicated simulators build issue
22-
# happening while using Xcode 8.2 + iOS simulator 10.2 configuration. Be
23-
# sure to check GitHub issue #7031
24-
# (https://github.com/travis-ci/travis-ci/issues/7031) for updates and, as
25-
# soon as the Travis team fix the issue, remove this line.
26-
- xcrun simctl delete D0257C83-DB81-4567-93EC-4C6DF23DC24C
27-
2821
script: xcodebuild -project "$PROJECT" -scheme "$SCHEME" -sdk "$SDK" -destination "$DESTINATION" -configuration Debug test | xcpretty -f `xcpretty-travis-formatter` && exit ${PIPESTATUS[0]}

Classes/GLCollectionTableViewCell.swift

Lines changed: 35 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -30,35 +30,58 @@
3030
import UIKit
3131

3232
class GLIndexedCollectionViewFlowLayout: UICollectionViewFlowLayout {
33-
var paginatedScroll: Bool?
33+
fileprivate var paginatedScroll: Bool?
3434

3535
override func awakeFromNib() {
3636
super.awakeFromNib()
3737
}
3838

3939
override func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint {
40+
// If the UICollectionView has paginatedScroll set to false there is no
41+
// need to apply any pagination logic, so we simply return the current
42+
// proposedContentOffset coordinates.
4043
guard paginatedScroll == true else {
4144
return CGPoint(x: proposedContentOffset.x, y: 0)
4245
}
4346

47+
// It's not a bad idea to shield us for some strange cases where the
48+
// UICollectionView won't be there for any reason, since it comes in an
49+
// Optional flavor. If the UICollectionView won't be available we return
50+
// the current proposedContentOffset coordinates and exit.
51+
guard let collectionView: UICollectionView = collectionView else {
52+
return CGPoint(x: proposedContentOffset.x, y: 0)
53+
}
54+
55+
let scannerFrame: CGRect = CGRect(x: proposedContentOffset.x,
56+
y: 0,
57+
width: collectionView.bounds.width,
58+
height: collectionView.bounds.height)
59+
60+
// If there is no UICollectionViewLayoutAttributes for the given
61+
// scannerFrame there is no reason to calculate a paginated layout for
62+
// it, so we the current proposedContentOffset coordinates.
63+
guard let layoutAttributes: [UICollectionViewLayoutAttributes] = super.layoutAttributesForElements(in: scannerFrame) else {
64+
return CGPoint(x: proposedContentOffset.x, y: 0)
65+
}
66+
4467
// To make paginated scrolling work fine this CGFloat below MUST be
4568
// equal to the value set in the insetForSectionAt method of
4669
// UICollectionView's UICollectionViewDelegate Flow Layout.
4770
let collectionViewInsets: CGFloat = 10.0
4871

49-
// Since UICollectionViewFlowLayout proposedContentOffset coordinates
72+
// Since UICollectionViewFlowLayout's proposedContentOffset coordinates
5073
// won't take count of any UICollectionView UIEdgeInsets values we need
5174
// to fix it by adding collectionViewInsets to the .x coordinate.
5275
//
53-
// Note: This will only cover horizontal scrolling and pagination, if you
54-
// need vertical pagination replace the .x coordinate with .y and update
55-
// collectionViewInsets value with the appropriate one.
76+
// Note: This will only cover horizontal scrolling and pagination, if
77+
// you need vertical pagination replace the .x coordinate with .y and
78+
// update collectionViewInsets value with the appropriate one.
5679
let proposedXCoordWithInsets: CGFloat = proposedContentOffset.x + collectionViewInsets
5780

5881
// We now create a variable and we assign a very high CGFloat to it (a
59-
// big number here is needed to cover very large
60-
// UICollectionViewContentSize cases). This var will hold the needed
61-
// horizontal adjustment to make the UICollectionView paginate scroll.
82+
// to cover very large UICollectionViewContentSize cases).
83+
// This var will hold the needed horizontal adjustment to make the
84+
// UICollectionView paginate scroll.
6285
var offsetCorrection: CGFloat = .greatestFiniteMagnitude
6386

6487
// Now we loop through all the different layout attributes of the
@@ -67,22 +90,11 @@ class GLIndexedCollectionViewFlowLayout: UICollectionViewFlowLayout {
6790
// cell which needs the least offsetCorrection value: it will mean that
6891
// it's the first cell on the left of the screen which will give
6992
// pagination.
70-
for layoutAttribute: UICollectionViewLayoutAttributes in super.layoutAttributesForElements(in: CGRect(x: proposedContentOffset.x, y: 0, width: collectionView!.bounds.width, height: collectionView!.bounds.height))! {
71-
// layoutAttributesForElements may contain all sort of layout
93+
layoutAttributes.forEach { (layoutAttribute) in
94+
// UICollectionViewLayoutAttributes may contain all sort of layout
7295
// attributes so we need to check if it belongs to a
7396
// UICollectionViewCell, otherwise logic won't work.
7497
if layoutAttribute.representedElementCategory == .cell {
75-
// Since UICollectionViewFlowLayout's UICollectionView comes in
76-
// an Optional flavour and we will need to get it's frame size
77-
// down below, it's not a bad idea to shield us from those very
78-
// strange cases in which the UICollectionView won't be there
79-
// (for whatever reason) and exit the loop since it is useless
80-
// to calculate an offsetCorrection for a non-existent
81-
// UICollectionView.
82-
guard let collectionView = collectionView else {
83-
break
84-
}
85-
8698
// To accurately calculate the offsetCorrection we will check
8799
// only the cells contained in one half of UICollectionView's
88100
// width, following the scrolling direction. The check will be
@@ -91,7 +103,7 @@ class GLIndexedCollectionViewFlowLayout: UICollectionViewFlowLayout {
91103
let discardableScrollingElementsFrame: CGFloat = collectionView.contentOffset.x + (collectionView.frame.size.width / 2)
92104

93105
if (layoutAttribute.center.x <= discardableScrollingElementsFrame && velocity.x > 0) || (layoutAttribute.center.x >= discardableScrollingElementsFrame && velocity.x < 0) {
94-
continue
106+
return
95107
}
96108

97109
if abs(layoutAttribute.frame.origin.x - proposedXCoordWithInsets) < abs(offsetCorrection) {
@@ -160,7 +172,7 @@ class GLCollectionTableViewCell: UITableViewCell {
160172
collectionFlowLayout.scrollDirection = .horizontal
161173

162174
collectionView = GLIndexedCollectionView(frame: .zero, collectionViewLayout: collectionFlowLayout)
163-
collectionView.register(UINib(nibName: "GLIndexedCollectionViewCell", bundle: nil), forCellWithReuseIdentifier: "collectionViewCellID")
175+
collectionView.register(UINib(nibName: "GLIndexedCollectionViewCell", bundle: nil), forCellWithReuseIdentifier: GLIndexedCollectionViewCell.identifier)
164176
collectionView.backgroundColor = .white
165177
collectionView.showsHorizontalScrollIndicator = false
166178
collectionView.showsVerticalScrollIndicator = false

Classes/GLIndexedCollectionViewCell.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030
import UIKit
3131

3232
class GLIndexedCollectionViewCell: UICollectionViewCell {
33+
static let identifier: String = "collectionViewCellID"
34+
3335
override func awakeFromNib() {
3436
super.awakeFromNib()
3537
// Initialization code

Classes/GLTableCollectionViewController.swift

Lines changed: 31 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,14 @@
2929

3030
import UIKit
3131

32-
class GLTableCollectionViewController: UITableViewController, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
33-
// This string constant will be the cellIdentifier for the UITableViewCells
34-
// holding the UICollectionView, it's important to append "_section#" to it
35-
// so we can understand which cell is the one we are looking for in the
36-
// debugger. Look in UITableView's data source cellForRowAt method for more
37-
// explanations about the UITableViewCell reuse handling.
38-
let tableCellID: String = "tableViewCellID_section_#"
39-
let collectionCellID: String = "collectionViewCellID"
32+
final class GLTableCollectionViewController: UITableViewController, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
33+
// This static string constant will be the cellIdentifier for the
34+
// UITableViewCells holding the UICollectionView, it's important to append
35+
// "_section#" to it so we can understand which cell is the one we are
36+
// looking for in the debugger. Look in UITableView's data source
37+
// cellForRowAt method for more explanations about the UITableViewCell reuse
38+
// handling.
39+
static let tableCellID: String = "tableViewCellID_section_#"
4040

4141
let numberOfSections: Int = 20
4242
let numberOfCollectionsForRow: Int = 1
@@ -66,7 +66,7 @@ class GLTableCollectionViewController: UITableViewController, UICollectionViewDa
6666
let randomGreen: CGFloat = CGFloat(arc4random_uniform(256))
6767
let randomBlue: CGFloat = CGFloat(arc4random_uniform(256))
6868

69-
if (randomRed == 255.0 && randomGreen == 255.0 && randomBlue == 255.0) {
69+
if randomRed == 255.0 && randomGreen == 255.0 && randomBlue == 255.0 {
7070
randomRed = CGFloat(arc4random_uniform(128))
7171
}
7272

@@ -109,10 +109,10 @@ class GLTableCollectionViewController: UITableViewController, UICollectionViewDa
109109
// will have a different UICollectionView with UICollectionViewCells in
110110
// it and UITableView reuse won't work as expected giving back wrong
111111
// cells.
112-
var cell: GLCollectionTableViewCell? = tableView.dequeueReusableCell(withIdentifier: tableCellID + indexPath.section.description) as? GLCollectionTableViewCell
112+
var cell: GLCollectionTableViewCell? = tableView.dequeueReusableCell(withIdentifier: GLTableCollectionViewController.tableCellID + indexPath.section.description) as? GLCollectionTableViewCell
113113

114114
if cell == nil {
115-
cell = GLCollectionTableViewCell(style: .default, reuseIdentifier: tableCellID + indexPath.section.description)
115+
cell = GLCollectionTableViewCell(style: .default, reuseIdentifier: GLTableCollectionViewController.tableCellID + indexPath.section.description)
116116

117117
// Configure the cell...
118118
cell!.selectionStyle = .none
@@ -126,6 +126,8 @@ class GLTableCollectionViewController: UITableViewController, UICollectionViewDa
126126
return "Section: " + section.description
127127
}
128128

129+
// MARK: <UITableView Delegate>
130+
129131
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
130132
return 88
131133
}
@@ -138,8 +140,6 @@ class GLTableCollectionViewController: UITableViewController, UICollectionViewDa
138140
return 0.0001
139141
}
140142

141-
// MARK: <UITableView Delegate>
142-
143143
override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
144144
guard let cell: GLCollectionTableViewCell = cell as? GLCollectionTableViewCell else {
145145
return
@@ -159,10 +159,16 @@ class GLTableCollectionViewController: UITableViewController, UICollectionViewDa
159159
}
160160

161161
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
162-
let cell: GLIndexedCollectionViewCell = collectionView.dequeueReusableCell(withReuseIdentifier: collectionCellID, for: indexPath) as! GLIndexedCollectionViewCell
162+
guard let cell: GLIndexedCollectionViewCell = collectionView.dequeueReusableCell(withReuseIdentifier: GLIndexedCollectionViewCell.identifier, for: indexPath) as? GLIndexedCollectionViewCell else {
163+
fatalError("UICollectionViewCell must be of GLIndexedCollectionViewCell type")
164+
}
165+
166+
guard let indexedCollectionView: GLIndexedCollectionView = collectionView as? GLIndexedCollectionView else {
167+
fatalError("UICollectionView must be of GLIndexedCollectionView type")
168+
}
163169

164170
// Configure the cell...
165-
cell.backgroundColor = colorsDict[(collectionView as! GLIndexedCollectionView).indexPath.section]?[indexPath.row]
171+
cell.backgroundColor = colorsDict[indexedCollectionView.indexPath.section]?[indexPath.row]
166172

167173
return cell
168174
}
@@ -175,7 +181,7 @@ class GLTableCollectionViewController: UITableViewController, UICollectionViewDa
175181
let collectionRightInset: CGFloat = 10
176182

177183
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
178-
return UIEdgeInsetsMake(collectionTopInset, collectionLeftInset, collectionBottomInset, collectionRightInset)
184+
return UIEdgeInsets(top: collectionTopInset, left: collectionLeftInset, bottom: collectionBottomInset, right: collectionRightInset)
179185
}
180186

181187
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
@@ -197,17 +203,17 @@ class GLTableCollectionViewController: UITableViewController, UICollectionViewDa
197203
// MARK: <UICollectionView Delegate>
198204

199205
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
200-
206+
201207
}
202208

203-
/*
204-
// MARK: <Navigation>
209+
/*
210+
// MARK: <Navigation>
205211

206-
// In a storyboard-based application, you will often want to do a little
212+
// In a storyboard-based application, you will often want to do a little
207213
// preparation before navigation
208-
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
209-
// Get the new view controller using segue.destinationViewController.
210-
// Pass the selected object to the new view controller.
211-
}
212-
*/
214+
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
215+
// Get the new view controller using segue.destinationViewController.
216+
// Pass the selected object to the new view controller.
217+
}
218+
*/
213219
}

GLTableCollectionView.xcodeproj/project.pbxproj

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@
115115
747CF8F51DE6EB010051A5FF /* Sources */,
116116
747CF8F61DE6EB010051A5FF /* Frameworks */,
117117
747CF8F71DE6EB010051A5FF /* Resources */,
118+
EF73511D1E8E9B5800F73EDB /* SwiftLint */,
118119
);
119120
buildRules = (
120121
);
@@ -205,6 +206,23 @@
205206
};
206207
/* End PBXResourcesBuildPhase section */
207208

209+
/* Begin PBXShellScriptBuildPhase section */
210+
EF73511D1E8E9B5800F73EDB /* SwiftLint */ = {
211+
isa = PBXShellScriptBuildPhase;
212+
buildActionMask = 2147483647;
213+
files = (
214+
);
215+
inputPaths = (
216+
);
217+
name = SwiftLint;
218+
outputPaths = (
219+
);
220+
runOnlyForDeploymentPostprocessing = 0;
221+
shellPath = /bin/sh;
222+
shellScript = "if which swiftlint >/dev/null; then\n swiftlint\nelse\n echo \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi";
223+
};
224+
/* End PBXShellScriptBuildPhase section */
225+
208226
/* Begin PBXSourcesBuildPhase section */
209227
747CF8F51DE6EB010051A5FF /* Sources */ = {
210228
isa = PBXSourcesBuildPhase;

GLTableCollectionView/AppDelegate.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
import UIKit
3131

3232
@UIApplicationMain
33-
class AppDelegate: UIResponder, UIApplicationDelegate {
33+
final class AppDelegate: UIResponder, UIApplicationDelegate {
3434
var window: UIWindow?
3535

3636
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {

GLTableCollectionView/Info.plist

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
<key>CFBundlePackageType</key>
1616
<string>APPL</string>
1717
<key>CFBundleShortVersionString</key>
18-
<string>1.69</string>
18+
<string>1.70</string>
1919
<key>CFBundleVersion</key>
2020
<string>1</string>
2121
<key>LSRequiresIPhoneOS</key>

GLTableCollectionViewTests/GLTableCollectionViewTests.swift

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -58,17 +58,14 @@ class GLTableCollectionViewTests: XCTestCase {
5858
XCTAssertGreaterThan(tableCollectionView.numberOfCollectionItems, 0,
5959
"numberOfCollectionItems was: \(tableCollectionView.numberOfCollectionItems)\nThere must be at least one GLIndexedCollectionViewCell")
6060

61-
XCTAssertNotEqual(tableCollectionView.tableCellID, "",
62-
"tableCellID was: \(tableCollectionView.tableCellID)\nUITableViewCell's cellIdentifier must not be empty")
61+
XCTAssertNotEqual(GLTableCollectionViewController.tableCellID, "",
62+
"tableCellID was: \(GLTableCollectionViewController.tableCellID)\nUITableViewCell's cellIdentifier must not be empty")
6363

64-
XCTAssertTrue(tableCollectionView.tableCellID.hasSuffix("_section_#"),
65-
"tableCellID was: \(tableCollectionView.tableCellID)\nUITableViewCell's cellIdentifier must end with section number suffix")
64+
XCTAssertTrue(GLTableCollectionViewController.tableCellID.hasSuffix("_section_#"),
65+
"tableCellID was: \(GLTableCollectionViewController.tableCellID)\nUITableViewCell's cellIdentifier must end with section number suffix")
6666

67-
XCTAssertTrue((tableCollectionView.tableCellID.components(separatedBy: "#").count - 1) == 1,
68-
"tableCellID was: \(tableCollectionView.tableCellID)\nUITableViewCell's cellIdentifier must contain only one # in it")
69-
70-
XCTAssertNotEqual(tableCollectionView.collectionCellID, "",
71-
"The cellIdentifier for the UICollectionCells should not be empty")
67+
XCTAssertTrue((GLTableCollectionViewController.tableCellID.components(separatedBy: "#").count - 1) == 1,
68+
"tableCellID was: \(GLTableCollectionViewController.tableCellID)\nUITableViewCell's cellIdentifier must contain only one # in it")
7269
}
7370

7471
func testRandomColorsGeneration() {
@@ -106,7 +103,7 @@ class GLTableCollectionViewTests: XCTestCase {
106103

107104
for tableViewCell: GLCollectionTableViewCell in visibleCells as! [GLCollectionTableViewCell] {
108105
XCTAssertTrue(Int(tableViewCell.reuseIdentifier!.components(separatedBy: "#").last!)! >= 0,
109-
"GLCollectionTableViewCell cellIdentifier was: \(tableViewCell.reuseIdentifier)\nGLCollectionTableViewCell's cellIdentifier must end with a positive integer")
106+
"GLCollectionTableViewCell cellIdentifier was: \(String(describing: tableViewCell.reuseIdentifier))\nGLCollectionTableViewCell's cellIdentifier must end with a positive integer")
110107
}
111108
}
112109

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ var paginationEnabled: Bool = true
5050
- Xcode 8.0+
5151
- Swift 3.0+
5252
- iOS 8.0+
53+
- [SwiftLint](https://github.com/realm/SwiftLint) (Optional, but _highly_ suggested)
5354

5455
## Note
5556
GLTableCollectionView is written using Swift 3.0 so it would only support iOS 8.0+ due to Swift 3 language compatibility, if you use Swift 2.0 in your project or you need iOS 7.0+ compatibility GLTableCollectionView will work too, but you **must** convert `UITableView` and `UICollectionView` Data Source and Delegate methods signatures before building your code or Xcode won't compile.

0 commit comments

Comments
 (0)