Monday, March 18, 2019

Display images horizontally in a listbox with UICollectionView

I'm using Xcode 9 and swift 3 to developing a pet project. It requires showing a list of images horizontally at the bottom of the screen as shown in the image below.



1. Add UICollectionView in Interface Builder


- Drag UICollectionView from the Object Library and drop it on the View Controller and set appropriate constraints (related to its superview).

- Drag UIImageView from the Object Library and drop it on the UICollectionViewCell come with the UICollectionView object and set appropriate constraints related to the UICollectionViewCel. (Don't set constraints for the UICollectionViewCell)


2. Create a custom UICollectionViewCell class


- Select File menu > New > File...
- Select Cocoa Touch Class and click Next
- Set "Class" to ImageCollectionViewCell then "Subclass of" to UICollectionViewCell and make sure the "Also create XIB file" checkbox is unchecked cause we don't need it.

- Open ImageCollectionViewCell.swift file and create an outlet connected to the UIImageView control added in the step above.

import UIKit

class ImageCollectionViewCell: UICollectionViewCell {
        
    @IBOutlet weak var imageView: UIImageView!
}
 

- Within the storyboard, select the UICollectionViewCell control then open Identity Inspector and set Class under Custom Class section to ImageCollectionViewCell. After that, open Attributes Inspector and set Identifier under Collection Reusable View section to ImageCollectionViewCell.

3. Make the ViewController class conform to UICollectionViewDelegate and UICollectionViewDataSource


Create an outlet connected the UICollectionView control in the Interface Builder to the ViewController class and update it as following:


import Foundation
import UIKit

public class ViewController : UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {
    
    @IBOutlet weak var collectionView: UICollectionView!
    
    private var images = [
        UIImage(named:"theme_1"),
        UIImage(named:"theme_2"),
        UIImage(named:"theme_3"),
        UIImage(named:"theme_4")
    ]
    
    public override func viewDidLoad() {
        collectionView.delegate = self
        collectionView.dataSource = self
    }
    
    public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return images.count
    }
    
    public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ImageCollectionViewCell", for: indexPath) as! ImageCollectionViewCell
        cell.imageView.image = images[indexPath.row]
        return cell
    }
    
}
 

Note that any operations related to the sizes of cell's subviews should not be done in those methods of UICollectionViewCellDelegate because the frame and bounds properties are not finalized yet. Do it in layoutSubviews() method of the cell instead.

Setting the size of the cell in the method below does not have any effects.

public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
}
 


Setting the size of each cell and space between them


The ViewController must conform to UICollectionViewDelegateFlowLayout protocol and implement its methods.

The code snippets below is an example of how to set the size of a cell:

    public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        // The height and width of the container view (stackview)
        // of the four buttons in the cell (xib file)
        // should be the same to make them look completely circles.
        // Then, the cell's width should be equal to cell's height
        // plus the tick buttons's width.
        // We have a constraint in the IB to define the tick button's width
        // equal to one-fourth width of the container view
        // so this size will fit them right.
        let cellHeight = collectionView.bounds.height - 10
        let tickButtonWidth = cellHeight / 4
        let cellWidth = tickButtonWidth + cellHeight
        return CGSize(width: cellWidth, height: cellHeight)
    }
 

This is an example of how to set the space between cell in the same row:

    public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
        return 25
    } 

The example below tells how to set the space between the collection view and its contents:
    
    public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
        return UIEdgeInsets(top: 0, left: 10, bottom: 0, right: 10)
    } 
    



References
https://www.youtube.com/watch?v=SL1ZmIp83iI

No comments:

Post a Comment