How to add PageControl inside UICollectionView Image Scrolling
Solution 1
Here you have a complete class with Page Control pagination in a horizontal collection view. This is working on one of my applications, right now, and is working correctly. If you cannot get it work, do feel free to ask me and I'll help you.
First, in the Storyboard you have to set up your CollectionView with:
Layout: Flow
Scroll Direction: Horizontal
Scrolling enabled
Paging enabled
@IBOutlet weak var collectionView: UICollectionView! //img: 77
@IBOutlet weak var pageControl: UIPageControl!
var thisWidth:CGFloat = 0
override func awakeFromNib() {
super.awakeFromNib()
thisWidth = CGFloat(self.frame.width)
collectionView.delegate = self
collectionView.dataSource = self
pageControl.hidesForSinglePage = true
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 10
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "YourCell", for: indexPath)
return cell
}
func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
self.pageControl.currentPage = indexPath.section
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
thisWidth = CGFloat(self.frame.width)
return CGSize(width: thisWidth, height: self.frame.height)
}
Solution 2
I'm not a fan of the accepted answer. From time to time, willDisplay cell
will return the wrong page for the page control depending on users interaction.
What I use:
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
pageControl.currentPage = Int(scrollView.contentOffset.x) / Int(scrollView.frame.width)
}
This will update the page after the user has finished scrolling thus making the currentPage
of the pageControl
more accurate.
Solution 3
For a more responsive UIPageControl, I prefer to use scrollViewDidScroll
and calculating the offset with regards to the horizontal center of the scrollView.
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let offSet = scrollView.contentOffset.x
let width = scrollView.frame.width
let horizontalCenter = width / 2
pageControl.currentPage = Int(offSet + horizontalCenter) / Int(width)
}
Solution 4
Swift 5 Very Smooth working
//MARK:- For Display the page number in page controll of collection view Cell
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let visibleRect = CGRect(origin: self.collectionview.contentOffset, size: self.collectionview.bounds.size)
let visiblePoint = CGPoint(x: visibleRect.midX, y: visibleRect.midY)
if let visibleIndexPath = self.collectionview.indexPathForItem(at: visiblePoint) {
self.pageControl.currentPage = visibleIndexPath.row
}
}
Solution 5
Waiting for scrollViewDidEndDecelerating
results in a slow update to the UIPageControl
. If you want a more responsive UI, I suggest instead implementing scrollViewWillEndDragging(_:withVelocity:targetContentOffset:)
.
Swift 4 example where each collection view section is a page:
override func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
if let collectionView = scrollView as? ScoreCollectionView,
let section = collectionView.indexPathForItem(at: targetContentOffset.pointee)?.section {
self.pageControl.currentPage = section
}
}
Related videos on Youtube
Comments
-
SwiftDeveloper over 2 years
I have
UICollectionView
Horizontal Image listing codes. I want to addPageControl
when scrolling images will shows, I added pagecontrol selector andIBOutlet
but how can I integrate it betweenUICollecitonView
?My codes are below:
class ViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout { @IBOutlet weak var View : DesignableView! @IBOutlet var collectionView: UICollectionView! @IBOutlet var collectionViewLayout: UICollectionViewFlowLayout! @IBOutlet open weak var pageControl: UIPageControl? { didSet { pageControl?.addTarget(self, action: #selector(ViewController.pageChanged(_:)), for: .valueChanged) } } override func viewDidLoad() { super.viewDidLoad() pageControl?.numberOfPages = 11 } func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return 11; } func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell: ImageCollectionViewCell = collectionView.dequeueReusableCell(withReuseIdentifier: "ImageCollectionViewCell", for: indexPath) as! ImageCollectionViewCell cell.label.text = "Cell \(indexPath.row)" cell.backgroundImageView.image = UIImage(named: "Parallax \(indexPath.row + 1)") // Parallax cell setup cell.parallaxTheImageViewScrollOffset(self.collectionView.contentOffset, scrollDirection: self.collectionViewLayout.scrollDirection) return cell } @IBAction open func pageChanged(_ sender: UIPageControl) { print(sender.currentPage) } // MARK: Delegate func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { return collectionView.bounds.size; } // MARK: Scrolling func scrollViewDidScroll(_ scrollView: UIScrollView) { // Parallax visible cells for cell: ImageCollectionViewCell in collectionView.visibleCells as! [ImageCollectionViewCell] { cell.parallaxTheImageViewScrollOffset(self.collectionView.contentOffset, scrollDirection: self.collectionViewLayout.scrollDirection) } } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } }
-
SwiftDeveloper over 7 yearsdude dont work with pagecontrol when i added func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return self.myarray.count // HERE dont work page control }
-
J Curti over 7 yearsThat's because in order to make a page for each item, you have to use sections, not rows
-
gasparuff almost 7 yearsBut with this solution, when the user swipes to the next page and then swipes back again without lifting his finger, the pageControl shows the wrong page. I think you should consider @luke's answer
-
Nico over 6 yearsThat's something you should clearly state in your answer
-
Axy over 6 yearsThis should be the only accepted answer since it's the most clean and responsive way to do it.
-
Deamon over 6 yearsI have to substitute
section
foritem
-
Deamon over 6 yearsIf you swipe fast enough, the current page can produce the wrong result.
-
Hardik Darji about 6 yearsWorking as I want. Thx
-
Sarthak Mishra almost 6 yearsBest solution! Responsive and accurate
-
Codenator81 over 5 yearsShould be best answer
-
Ben Shabat over 5 yearshow to make it work with a right to left pageControl?
-
sangavi over 5 yearsAwesome search for full day finally got great answer
-
Rick van der Linde about 5 yearsfyi row is for table views, item is for collection views.
-
Graham Perks almost 5 yearsNoticeably better than using the laggy
scrollViewDidEndDecelerating
solution. -
user3788747 over 4 yearsLuke's solution somehow does not work any more for me. But David's answer works and it saved my life, ty.
-
Antoine El Murr over 4 yearsThis should be the accepted answer, seriously I have seen the answer above and it took me like 3 hours to realize that the correct answer is underneath the accepted one
-
Jason Aller about 4 yearsWhen answering a three year old question with eight other answers you need to explain what is new and different about your answer. Proper formatting for a block of code is not the same and formatting each line as a section of inline code. Code only answers need explanation of how and why they work.
-
Khushtar parvez about 4 yearsThis is another method if you can Compare to Another
-
Prashanth Thota almost 4 years@RickvanderLinde even though it is mentioned as row instead of item it works fine.
-
Lal Krishna over 3 yearsThis works smoothly if we disabled
UIPageControl
's userInteraction. For those who needs to support pagecontrol's action, put this calculation inscrollViewDidEndDecelerating
-
user2990765 over 3 yearsThe problem I am facing is that the collection view always starts with the first page. How do I initialise the collection view to start somewhere from the middle page?