How to install and use this module.
CenteredCollectionView is available through Swift Package Manager, CocoaPods and Carthage.
To install it with Swift Package Manager, add the URL https://github.com/BenEmdon/CenteredCollectionView
in Xcode Add Package Dependency assistant ; or add to your own Package.swift
:
dependencies: [
.package(url: "https://github.com/BenEmdon/CenteredCollectionView", from: "2.2.2")
]
To install it with Cocoapods, add the following line to your Podfile
:
pod "CenteredCollectionView"
To install it with Carthage, add the following line to your Cartfile
:
github "BenEmdon/CenteredCollectionView"
-
To start off lets add a
UICollectionView
to our controller, and lay it out however you want it. -
Next lets set the
UICollectionView
's custom layout to beCenteredCollectionViewFlowLayout
. -
Next we can optionally layout the prototype item. Note that this doesn't determine the item's size.
-
Let's create an example cell subclass that contains the views we want to present. Create a new file named "UserCollectionViewCell", with the following code:
import UIKit class UserCollectionViewCell: UICollectionViewCell { }
Next, set the prototype item in the Storyboard to subclass from here:
Finally, add a label to the cell and create a corresponding outlet in the
UserCollectionViewCell
subclass. -
Next lets dive in to the code use:
import CenteredCollectionView
class ViewController: UIViewController {
@IBOutlet weak var collectionView: UICollectionView!
// The width of each cell with respect to the screen.
// Can be a constant or a percentage.
let cellPercentWidth: CGFloat = 0.7
// A reference to the `CenteredCollectionViewFlowLayout`.
// Must be aquired from the IBOutlet collectionView.
var centeredCollectionViewFlowLayout: CenteredCollectionViewFlowLayout!
override func viewDidLoad() {
super.viewDidLoad()
// Get the reference to the `CenteredCollectionViewFlowLayout` (REQUIRED STEP)
centeredCollectionViewFlowLayout = collectionView.collectionViewLayout as! CenteredCollectionViewFlowLayout
// Modify the collectionView's decelerationRate (REQUIRED STEP)
collectionView.decelerationRate = UIScrollViewDecelerationRateFast
// Assign delegate and data source
collectionView.delegate = self
collectionView.dataSource = self
// Configure the required item size (REQUIRED STEP)
centeredCollectionViewFlowLayout.itemSize = CGSize(
width: view.bounds.width * cellPercentWidth,
height: view.bounds.height * cellPercentWidth * cellPercentWidth
)
// Configure the optional inter item spacing (OPTIONAL STEP)
centeredCollectionViewFlowLayout.minimumLineSpacing = 20
// Get rid of scrolling indicators
collectionView.showsVerticalScrollIndicator = false
collectionView.showsHorizontalScrollIndicator = false
}
}
As with any UICollectionView
, you'll also need to conform to the UICollectionViewDelegate
and UICollectionViewDataSource
protocols, as follows:
// Here's an example model we'll use.
struct User {
var name: String
}
class ViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {
// ... properties as before
// Instance of our example data model
var users = [User]()
override func viewDidLoad() {
// ...
// Flush the model with some example data
users.append(User("User1"))
users.append(User("User2"))
users.append(User("User3"))
}
// MARK: UICollectionViewDelegate
// Now, we'll conform to the delegates that we promised in the viewDidLoad earlier
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return users.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
// Grab our cell from dequeueReusableCell, wtih the same identifier we set in our storyboard.
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as? UserCollectionViewCell
// Error checking, if our cell is somehow not able to be cast
guard let userCell = cell else {
print("Unable to instantiate user cell at index \(indexPath.row)")
return cell
}
// Give the current cell the corresponding data it needs from our model
userCell.label.text = users[indexPath.row].name
return userCell
}
}
class ViewController: UIViewController {
let centeredCollectionViewFlowLayout = CenteredCollectionViewFlowLayout()
let collectionView: UICollectionView
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
// Initialize the collectonView with the `CenteredCollectionViewFlowLayout` (REQUIRED STEP)
collectionView = UICollectionView(centeredCollectionViewFlowLayout: centeredCollectionViewFlowLayout)
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
}
override func viewDidLoad() {
super.viewDidLoad()
// Assign delegate and data source
collectionView.delegate = self
collectionView.dataSource = self
// Layout subviews (not shown)
...
// Register collection cells (REQUIRED STEP)
collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: String(describing: UICollectionViewCell.self))
// Configure the required item size (REQUIRED STEP)
centeredCollectionViewFlowLayout.itemSize = CGSize(
width: view.bounds.width * cellPercentWidth,
height: view.bounds.height * cellPercentWidth * cellPercentWidth
)
// Configure the optional inter item spacing (OPTIONAL STEP)
centeredCollectionViewFlowLayout.minimumLineSpacing = 20
// Get rid of scrolling indicators
collectionView.showsVerticalScrollIndicator = false
collectionView.showsHorizontalScrollIndicator = false
}
}
// Delegate and datasource extensions
...
Scrolling to an Edge on Touch 🎡
Heres how you could trigger a scroll animation when a touch happens on an item that isn't the currentCenteredPage
:
extension ViewController: UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
// check if the currentCenteredPage is not the page that was touched
let currentCenteredPage = centeredCollectionViewFlowLayout.currentCenteredPage
if currentCenteredPage != indexPath.row {
// trigger a scrollToPage(index: animated:)
centeredCollectionViewFlowLayout.scrollToPage(index: indexPath.row, animated: true)
}
}
}