I have a UICollectionView that has the following settings,
public CollectionView(CollectionLayout layout) : base(CGRect.Empty, layout)
{
RegisterClassForCell(typeof(CollectionCell), CollectionCell.CellIdentifier);
CollectionViewLayout = layout;
ShowsHorizontalScrollIndicator = false;
PagingEnabled = true;
}
The CollectionViewLayout is,
public CollectionLayout()
{
ScrollDirection = UICollectionViewScrollDirection.Horizontal;
MinimumInteritemSpacing = 0f;
MinimumLineSpacing = 0f;
ItemSize = new CGSize(UIScreen.MainScreen.Bounds.Width, 200f);
}
so the cells in the CollectionView are stretched so that a cell fills the CollectionView. The CollectionView is only horizontally scrollable.
Now I want to have a dotted page indicator instead of the scroll bar for the CollectionView. Is there anyway I can achieve this properly?
Simply add a UIPageControl
in storyboard.
Put it below (i.e., visible on top of) your collection view.
Link to it...
class YourVC: UIViewController, UICollectionViewDelegate,
UICollectionViewDataSource,
UICollectionViewDelegateFlowLayout {
@IBOutlet var collectionView: UICollectionView!
@IBOutlet var dots: UIPageControl!
Simply add a constraint centering it horizontally to the collection view, and add a constraint to align the bottoms.
That will give the standard positioning / spacing.
(Of course, you can place the dots anywhere you want, but that is the standard.)
Bizarrely the default colors for the dots are .. clear!
So set them to gray/black or whatever you wish:
Or you can do that in code:
override func viewDidLoad() {
super.viewDidLoad()
dots.pageIndicatorTintColor = .systemGray5
dots.currentPageIndicatorTintColor = .yourCorporateColor
}
Next. In numberOfItemsInSection
, add ...
func collectionView(_ collectionView: UICollectionView,
numberOfItemsInSection section: Int) -> Int {
let k = ... yourData.count, or whatever your count is
dots.numberOfPages = k
return k
}
Add this code:
func scrollViewDidScroll(_ scrollView: UIScrollView) {
dots.currentPage = Int(
(collectionView.contentOffset.x / collectionView.frame.width)
.rounded(.toNearestOrAwayFromZero)
)
)
}
You simply set the page in "scrollViewDidScroll".
In fact
• do not use scrollViewWillBeginDecelerating
• do not use scrollViewDidEndDecelerating
.
To see why: try it using either of those calls. Now skim quickly through many pages. Notice it does not work properly.
Simply use scrollViewDidScroll
for the correct, perfect result, including initialization.
You will often see this example code:
// wrong, do not do this
dots.currentPage = Int(collectionView.contentOffset.x) /
Int(collectionView.frame.width)
// wrong, do not do this
If you try that, it will result in the dots "jumping" in a non-standard way, as you skim through pages.
Best explanation is to try it and see.
For the usual, correct, Apple-style behavior as you scroll through or skim through the pages, the code is:
dots.currentPage = Int(
(collectionView.contentOffset.x / collectionView.frame.width)
.rounded(.toNearestOrAwayFromZero)
)
Final example...