Search code examples
swifttableviewcollectionview

Images In a Collection View


I am coding in Swift 3.2, and inside of a TableView Controller have a TableView (scrolling vertically), and each row of the table holds a CollectionView (scrolling horizontally).

I am not sure if it is acceptable coding practice, but I made my ViewController class inherit UITableViewController and UICollectionViewDelegate and UICollectionViewDataSource.

For now, I have a hard coded array of image names and would like three images to scroll horizontally in each collection view, with each row having distinct images. However, as of now each row shows the same three images ("11.png", "12.png", "13.png"), and I was wondering how to fix this.

Below is my ViewController class.

//for the tableView
let event = generateRandomData()

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return event.count
}

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
    return cell
}

override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
    guard let tableViewCell = cell as? TableViewCell else { return }
    tableViewCell.setCollectionViewDataSourceDelegate(self, forRow: indexPath.row)
}


//for the collectionView
var images: [String] = [
    "11.png", "12.png", "13.png",
    "21.png", "22.png", "23.png",
    "31.png", "32.png", "33.png",
    "41.png", "42.png", "43.png",
    "51.png", "52.png", "53.png",
    "61.png", "62.png", "63.png",
    "71.png", "72.png", "73.png",
    "81.png", "82.png", "83.png",
    "91.png", "92.png", "93.png",
    "101.png", "102.png", "103.png",
]

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return 3
}

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    collectionView.isPagingEnabled = true;      //makes the horizontal scrolling have no bounce and relatively have a better snap

    let myCell = collectionView.dequeueReusableCell(withReuseIdentifier: "collectionViewCell", for: indexPath as IndexPath) as! CollectionViewCell
    let myCellImage = UIImage(named: images[indexPath.row])
    myCell.eventImage.image = myCellImage

    return myCell
}

I am an amateur coder, so any help is greatly appreciated!


Solution

  • I am sure this problem already have an answer somewhere, but since I can't find that I'll just give one here.

    Your mistake is here:

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        /...
    
        let myCellImage = UIImage(named: images[indexPath.row]) //<< indexPath.row will return 0,1 and 2 for each of your collection view
    
        /...
    }
    

    Each collection view in your table view does not communicate amongst themselves to form a larger collective view. Since all of the are provided the int of 3 for numberOfItemsInSection and their numberOfSections defaulted to 1(you did not set any), each of them will request for item at indexpath (0,0), (0,1) and (0,2) when trying to populate their data.

    Your hardcoded array however, is an array with 30 items. So each collection view when requesting for cellForItemAt will only get 0,1 and 2 for images[indexPath.row]. Also you should use indexPath.item for collection view, indexPath.row is for table views, it may or may not work if used wrongly.

    Solution
    You can just set the tag property of the collection view to mark it's row:

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        /...
    
        //Make sure you have a subclass for UITableViewCell that have an IBOutlet that connects to the collection view
        cell.collectionView.tag = indexPath.row //Note that this only works in your situation where the table view have only 1 section.
        /...
    }
    

    Then split your array into a 2D array:

    var images = [
        ["11.png", "12.png", "13.png"],
        ["21.png", "22.png", "23.png"],
        ["31.png", "32.png", "33.png"],
        ["41.png", "42.png", "43.png"],
        ["51.png", "52.png", "53.png"],
        ["61.png", "62.png", "63.png"],
        ["71.png", "72.png", "73.png"],
        ["81.png", "82.png", "83.png"],
        ["91.png", "92.png", "93.png"],
        ["101.png", "102.png", "103.png"]
    ]
    

    Finally read the array in the collection view like:

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        /...
    
        let myCellImage = UIImage(named: images[myCell.tag][indexPath.item])
    
        /...
    }