IOS Swift – Custom horizontal CollectionView with images

Before reading I assume that you are familiar how to create storyboard items and include them in the Swift controller that is connected to storyboard view.

First we have to create a CollectionView in storyboard. To include CollectionView from storyboard add reference in Swift file class. Class must also inherit delegates from CollectionView. We will create some test data and show them in CollectionView.

I use string array for storing values to display inside of items and images (empty circle and filled circle to show them in CollectionView). Functions I will use are cellForItemAtIndexPath and numberOfItemsInSection. Make sure you have have dataSource and delegate from CollectionView set to ViewController in storyboard.

Here is an example how CollectionView looks:

class ViewController: UIViewController,  
        UICollectionViewDataSource, UICollectionViewDelegate 
{
  @IBOutlet var collectionView: UICollectionView!
  @IBOutlet var label: UILabel!
  @IBOutlet var countLabel: UILabel!

  var selectedCell: Int! = 0
  var stringArray: [String] = ["1", "2", "3", "4","5", "6", "7", "8",
    "9", "10", "11"]

  override func viewDidLoad() {
    super.viewDidLoad()

    selectedCell = 0
  }

  func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
  return stringArray.count
  }

  func collectionView(collectionView: UICollectionView, 
   cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell 
  {
    let cell = collectionView.dequeueReusableCellWithReuseIdentifier
       ("collectionCell", forIndexPath: indexPath) as! collectionViewCell

    cell.label.text = stringArray[indexPath.item]

    cell.layer.shouldRasterize = true;
    cell.layer.rasterizationScale = UIScreen.mainScreen().scale

    if(selectedCell != nil){
      if(indexPath.item == selectedCell){
        cell.image.image = UIImage(named: "FullCircle")!
        cell.label.textColor = UIColor.whiteColor()
      }
      else{
        cell.image.image = UIImage(named: "EmptyCircle")!
        cell.label.textColor = UIColor.blackColor()
      }
  }

    return cell
  }
}

Now we have to make CollectionView to show data horizontaly and we are going to disable paging so it doesn't show us pages at the bottom of CollectionView. We include it in viewDidLoad() function

timeCollectionView.showsHorizontalScrollIndicator = false  
timeCollectionView.pagingEnabled = false  

Next we have to create layout. I use LGHorizontalLinearFlowLayout, because we want bigger selected item in the middle of the screen than non selected items. Another great thing why we use this layout is that it also adds inset at the beginning and at the end of CollectionView.

Here is an example how to set up Layout:

self.collectionViewLayout = LGHorizontalLinearFlowLayout.configureLayout

(self.collectionView, itemSize: CGSizeMake(90, 90), minimumLineSpacing: 10)

Now it all runs smoothly and the middle item in CollectionView is bigger but it is still not selected. We have to create a function to select a middle item and change text label depending on selected option. First we have to find the item located in the centre of the screen and get it. It can be done with function indexPathForItemAtPoint. Now we loop through visible cells and set image of empty circle then we get centre cell which can be done with function cellForItemAtIndexPath. For selected cell we set image with full circle.

Function is now ready and we override a function of CollectionView's scrollview which is called scrollViewDidScroll

func scrollViewDidScroll(scrollView: UIScrollView) {  
  findCenterIndex(scrollView)
}

CollectionView is now scrollable and middle item is always selected only first item is not selected because of inset. We modify findCenterIndex function so that it checks first item:

else if(cell != nil)  
{
  let actualPosition = scrollView.panGestureRecognizer.
    translationInView(scrollView.superview)

  for cellView in self.collectionView.visibleCells()   
  {
    let currentCell = cellView as? collectionViewCell
    currentCell!.image.image = UIImage(named: "EmptyCircle")!
    currentCell!.label.textColor = UIColor.blackColor()

    if(currentCell == cell! && (selectedCell == 0 || 
    selectedCell == 1) && actualPosition.x > 0)
    {
      cell!.image.image = UIImage(named: "FullCircle")!
      selectedCell = collectionView.indexPathForCell(cell!)?.item
      self.countLabel.text = stringArray[selectedCell!]
    }
  }
}

Our collection view is now complete:

At the end we have built custom horizontal CollectionView with layout. You can find full example with a source code at https://bitbucket.org/evizija/ios-collectionview