[SOLVED] page control not working for UICollectionView inside UITableView

Issue

Im having issue with making page control work for a collection view which is inside table view. There are actually 2 collection views in the view controller, one is outside the tableView and other one is inside. I want page control for inside one. Let me share code below and then explain what is causing trouble:

class HomeViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {

     override func viewDidLoad() {
        super.viewDidLoad()

        //setup stories collection view
        let nib = UINib(nibName: "StoryCollectionViewCell", bundle: nil)
        cvStories.register(nib, forCellWithReuseIdentifier: "StoryCollectionViewCell")
        let layout1 = UICollectionViewFlowLayout()
        layout1.scrollDirection = .horizontal
        layout1.sectionInset = UIEdgeInsets(top: 5, left: 5, bottom: 5, right: 5)
        collectionViewStories.setCollectionViewLayout(layout1, animated: true)
        collectionViewStories.delegate = self
        collectionViewStories.dataSource = self
        
        tblHome.dataSource = self
        tblHome.delegate = self
     }


    // MARK: - Table View
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return posts.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        
        let cell = tblHome.dequeueReusableCell(withIdentifier: "HomeTableViewCell", for: indexPath) as! HomeTableViewCell
        
        cell.collectionViewPostImages.dataSource = self
        cell.collectionViewPostImages.delegate = self
        cell.collectionViewPostImages.tag = indexPath.row
        cell.collectionViewPostImages.reloadData()
        
        cell.pageControl.hidesForSinglePage = true
        cell.pageControl.numberOfPages = self.posts[cell.collectionViewPostImages.tag].imagesArray?.count ?? 0
        
        return cell
        
    }

    //MARK: - Collection View
    func numberOfSections(in collectionView: UICollectionView) -> Int {
        if collectionView == cvStories {
            return 2
        }
        else {
            return 1
        }
    }

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        if collectionView == collectionViewStories {
            return stories.count
        }
        else {
            return posts[collectionView.tag].imagesArray?.count ?? 0
        }
    }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        
        if collectionView == collectionViewStories {
            
            let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "StoryCollectionViewCell", for: indexPath) as! StoryCollectionViewCell
            //code to show stories
            return cell
            
        }
        else {
            
            let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "HomeCollectionViewCell", for: indexPath) as! HomeCollectionViewCell
            //code to show images
            return cell
            
        }
        
    }

}

//TableViewCell Class
class HomeTableViewCell: UITableViewCell {
   
    @IBOutlet weak var collectionViewPostImages: UICollectionView!
    @IBOutlet weak var pageControl: UIPageControl!
    
    var currentPage = 0
    
    override func awakeFromNib() {
    
        let flowLayout = UICollectionViewFlowLayout()
        flowLayout.itemSize = CGSize(width: UIScreen.main.bounds.size.width, height: cvPostImages.frame.size.height)
        flowLayout.scrollDirection = .horizontal
        flowLayout.minimumInteritemSpacing = 0
        flowLayout.minimumLineSpacing = 0
        collectionViewPostImages?.collectionViewLayout = flowLayout

        collectionViewPostImages.showsHorizontalScrollIndicator = false
        
        collectionViewPostImages.isPagingEnabled = true
        
    }
    
    //ScrollView delegate method
    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        let pageWidth = scrollView.frame.width
        self.currentPage = Int((scrollView.contentOffset.x + pageWidth / 2) / pageWidth)
        self.pageControl.currentPage = self.currentPage
    }
    
}

The whole code is like Instagram app, stories at top and posts with images in tableView. Whole code is in single View controller and everything works fine. Even dots (page number) are correct according to number of pages however when you swipe between them they do not change. I saw many solutions and in those pageControl.numberOfPages was used in cellForItemAt function but its out of scope for me so I just called it as cell.pageControl.numberOfPages in cellForRowAt instead. First time dealing with collectionView inside tableView so getting confused getting it worked.

Solution

The main problem is you use cell.collectionViewPostImages.delegate = self in HomeViewController but your method scrollViewDidScroll in cell HomeTableViewCell.

Collectionview’s own scrollview delegate methods triggering in UICollectionViewDelegate. Thats why scrollViewDidScroll is not triggered in your cell.

Solution is using scrollViewDidScroll in where you delegete the collectionview. It is HomeViewController

By the way, I dont recommend to use cell.collectionViewPostImages.dataSource = self cell.collectionViewPostImages.delegate = self in reusable cell. You dont want to make ...delegate = self on everytime when cell reused. You can take it in awakeFromNib in cell class

Answered By – Omer Tekbiyik

Answer Checked By – Cary Denson (BugsFixing Admin)

Leave a Reply

Your email address will not be published.