Infinite Scrolling using UICollectionView in Swift

27 / Jul / 2015 by Abhayam Rastogi 4 comments

Introduction

This tutorial is for iOS application developers to insert infinite scrolling in swift to achieve gallery effect using UICollectionView (Objective-C class). We will use UIScrollView delegate methods, UICollectionView & custom UICollectionViewCell for endless scrolling. You can add more items in collection view data source by adding images (.png) files in resource folder or can use web services to get data at run-time. Here we will play with UIScrollView delegate methods. We don’t need to add UIScrollView because UICollectionView is a subclass of UIScrollView.
Inheritance: NSObject->UIResponder->UIView->UIScrollView->UICollectionView.

 

Infinite Scrolling Using Collection View Demo Video

In this sample video you can see how image gallery can be implemented in iPhone using horizontal scrolling.

 

Getting Started

First of all create a new project iOS\Application\Single View Application template, click next. Enter “Infinite Scrolling” for the Product Name, Language “Swift”, Device “iPhone”, Core Data not checked and click next.
Then download the resource pack for this project e.i. images (.png) and store them in a “resource” folder or image assets.

Infinite (Endless) Scrolling Source Code

Let’s add Infinite Scrolling View Controller class to your project. To do this, go to File\New\File and select iOS\Source\Swift File. Name the file InfiniteScrollingViewController.swift, and click Create.

Creating your Views

UICollectionView: Drag a UICollectionView into your ViewController from Object library. It do you have basic knowledge of Autolayout then you can add constraints on collection view.
So far you have added views for you project. Open InfiniteScrollingViewController.swift.  You will see that the class has the following code in it already:
import UIKit
 
class ViewController: UIViewController {
 
  override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.
  }

  override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
  }
 
}

Adding Properties to your InfiniteScrolling View Controller

To do this, add these following properties to “InfiniteScrollingViewController” (right before viewDidLoad):
@IBOutlet weak var infiniteScrollingCollectionView: UICollectionView!
private let reuseIdentifier = "InfiniteScrollingCell"
private var photosUrlArray = [String]()
let WINDOW_WIDTH = UIScreen.mainScreen().bounds.width
let WINDOW_HEIGHT = UIScreen.mainScreen().bounds.height
Add the following in the ViewDidLoad:
self.title = "Infinite Scrolling"
self.automaticallyAdjustsScrollViewInsets = false
photosUrlArray = ["A_Photographer.jpg","A_Song_of_Ice_and_Fire.jpg","Another_Rockaway_Sunset.jpg","Antelope_Butte.jpg"]
infiniteScrollingCollectionView?.delegate = self
infiniteScrollingCollectionView?.dataSource = self

UICollectionViewDataSource

Let’s start with the data source. In InfiniteScrollingViewController.swift add an extension with the following datasource methods:
#pragma mark - UICollectionView Datasource
extension InfiniteScrollingViewController : UICollectionViewDataSource{
 func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
        return 1
    }
    
    func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return photosUrlArray.count
    }
    
    func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier, forIndexPath: indexPath) as! InfiniteScrollingCell
        let photoName = photoForIndexPath(indexPath)
        
        cell.configureCell(photoName)
        
        return cell
    }
}

UICollectionView Flow Layout Delegate Methods

In InfiniteScrollingViewController.swift, add an extension with the following delegate methods.Here we multiply collection view item’s height by 1.00346 to achieve aspect ration for images.
#pragma mark - UICollectionView Flow Layout Delegate
extension InfiniteScrollingViewController : UICollectionViewDelegateFlowLayout {
func collectionView(collectionView: UICollectionView,
        layout collectionViewLayout: UICollectionViewLayout,
        sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
            
            let size:CGSize = CGSizeMake(WINDOW_WIDTH, (WINDOW_WIDTH)*1.203460)
            return size
            
    }
    
    func collectionView(collectionView: UICollectionView,
        layout collectionViewLayout: UICollectionViewLayout,
        insetForSectionAtIndex section: Int) -> UIEdgeInsets {
            return UIEdgeInsetsMake(0, 0, 0, 0)
    }

}
Now before run your project add custom collection view cell.

Adding custom collection view cell

Go to File\New\File and select iOS\Source\Swift File. Name the file InfiniteScrollingCell.swift, and click Create with xib.
Open the Xib file and drag the UIImageView from the object library.

Adding Properties to your InfiniteScrolling Collection View cell

To do this, add these following properties to “InfiniteScrollingCell.swift” (right before awakeFromNib):
@IBOutlet weak var imageView: UIImageView!

Configure collection view cell

Add the following at the end your collection view cell class:
func configureCell(photoName:String){
imageView?.image = UIImage(named: photoName)
}

Adding endless scrolling logic here

Concept of endless scrolling is “Rotate an array by k elements”. To understand code in detail. Open the “InfiniteScrollingViewController.swift” and at the end of class add the following methods:
func photoForIndexPath(indexPath: NSIndexPath) -> String {
        return photosUrlArray[indexPath.row]
    }
    
    
    func reversePhotoArray(photoArray:[String], startIndex:Int, endIndex:Int){
        if startIndex >= endIndex{
            return
        }
        swap(&photosUrlArray[startIndex], &photosUrlArray[endIndex])
        
        reversePhotoArray(photosUrlArray, startIndex: startIndex + 1, endIndex: endIndex - 1)
    }

UIScrollView Delegate Methods

#pragma mark - UIScrollView Delegate
extension InfiniteScrollingViewController:UIScrollViewDelegate{

   func scrollViewDidEndDecelerating(scrollView: UIScrollView) {
        // Calculate where the collection view should be at the right-hand end item
      let fullyScrolledContentOffset:CGFloat = infiniteScrollingCollectionView.frame.size.width * CGFloat(photosUrlArray.count - 1)
      if (scrollView.contentOffset.x >= fullyScrolledContentOffset) {
            
      // user is scrolling to the right from the last item to the 'fake' item 1.
      // reposition offset to show the 'real' item 1 at the left-hand end of the collection view
       if photosUrlArray.count>2{  
         reversePhotoArray(photosUrlArray, startIndex: 0, endIndex: photosUrlArray.count - 1)
         reversePhotoArray(photosUrlArray, startIndex: 0, endIndex: 1)
         reversePhotoArray(photosUrlArray, startIndex: 2, endIndex: photosUrlArray.count - 1)
         var indexPath : NSIndexPath = NSIndexPath(forRow: 1, inSection: 0)               infiniteScrollingCollectionView.scrollToItemAtIndexPath(indexPath, atScrollPosition: .Left, animated: false)
            }
      }
      else if (scrollView.contentOffset.x == 0){
            
       if photosUrlArray.count>2{
        reversePhotoArray(photosUrlArray, startIndex: 0, endIndex: photosUrlArray.count - 1)
        reversePhotoArray(photosUrlArray, startIndex: 0, endIndex: photosUrlArray.count - 3)
        reversePhotoArray(photosUrlArray, startIndex: photosUrlArray.count - 2, endIndex: photosUrlArray.count - 1)
        var indexPath : NSIndexPath = NSIndexPath(forRow: photosUrlArray.count - 2, inSection: 0)
              infiniteScrollingCollectionView.scrollToItemAtIndexPath(indexPath, atScrollPosition: .Left, animated: false)
            }
        }
    }
}

Where to go from here ?

You can download the completed project from here.

Tag -

iOS
FOUND THIS USEFUL? SHARE IT

comments (4)

  1. DragonCherry

    Hi. I’ve implemented it recently for my personal purpose. Anyone can check my project below. Infinitely loop through views, recycle views, automatically fits current view on center, and so on.

    github.com/DragonCherry/HFSwipeView

    Reply
  2. Marko

    First I want to thank you for your nice and effective code. I have also found another project, implementing similar strategy for infinite scroll but I noticed in both projects small fluctuating (shivering) of images just a bit before scroll will stop. Do you have any advice hot to prevent this? Thank you, Marko

    Reply
    1. Abhayam Rastogi Post author

      Hi Marko,

      I have done some changes in the project’s scrollViewDidEndDeceleration & viewDidLod methods to reduce images fluctuation. Please try this drive.google.com/file/d/0BzGWvRnGZYdDQUlkMVdjTWZwbTQ/view?usp=sharing to download improved project.

      Reply

Leave a comment -