AdvancedPageControl: twelve page indicator animations for iOS
A simple yet powerful animated page control indicator for iOS.
At a glance
- What is it?
- AdvancedPageControl is a MIT licensed Swift library that gives an iOS app a set of animated page control indicators, with a drawer per effect and a scroll offset API so the indicator tracks a paging collection view. It suits app teams that want a distinctive onboarding or carousel indicator, and it is UIKit only with a CocoaPods-first distribution.
- Who is it for?
- AdvancedPageControl is the right choice for a UIKit team that wants a page indicator with more character than UIPageControl provides, since each effect is a separate drawer you can swap and the setPageOffset API lets the indicator track a paging scroll view without manual index bookkeeping.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Activity is slowing. The repository last received commits 6 months ago.
- What is it written in?
- Mainly Swift, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Page indicators as a design element, not a system control
AdvancedPageControl is described as a simple yet powerful page control indicator animations library for iOS, written in Swift. The framing matters. UIPageControl is a system control, and the system gives you one dot style, or in recent iOS versions a handful of built-in appearances. A library like this exists because the page indicator is often the most visible piece of chrome in an onboarding flow, a tutorial, or a product carousel, and a designer wants it to look like something.
The project positions itself as simple yet powerful, and the effect list is the substance of that claim. There are thirteen named effects: Color Blend, Drop, ExtendedDot, Jump, Scale, Slide, Swap, Worm, ThinWorm, ThinWormHead, Scrolling and Infinite, with the list in the README running from Color Blend through to Infinite. The worm variants are the ones that separate this from a stock control, since a worm is a stretched capsule that travels between positions rather than a dot that changes size.
The audience is app developers, not library developers. There is no theme system, no configuration file and no abstraction to learn. You pick a drawer class, assign it to the page control, and you have an indicator that looks designed rather than defaulted.
The scope is a single UI component, and the repository shows it: AdvancedPageControl/ holds the library, Example/ holds a demo project, Tests/ holds tests, and docs/ holds documentation, with a Package.swift, a podspec and a .swiftpm directory alongside.
The drawer pattern and how many knobs it exposes
The design centre of the library is the drawer. A drawer is an object that draws one effect, and the page control holds one and asks it to render. Assigning a drawer is a single line in viewDidLoad:
pageControl1.drawer = ColorBlendDrawer()The full set of drawer constructors available in the README is ColorBlendDrawer, DropDrawer, ExtendedDotDrawer, JumpDrawer, ScaleDrawer, SlideDrawer, SwapDrawer, ThinWormDrawer, ThinWormHeadsDrawer, WormDrawer, Scrolling and Infinite.
Each drawer is initialised with the same parameter set, and the README shows it on ScaleDrawer:
ScaleDrawer(numberOfPages:Int? = 5,
height: CGFloat? = 16,
width: CGFloat? = 16,
space: CGFloat? = 16,
radius: CGFloat? = 16,
currentItem: CGFloat? = 0,
indicatorColor: UIColor? = .red,
dotsColor: UIColor? = .lightGray)That parameter list is the whole configuration surface: how many pages, the height and width of the indicator, the spacing between items, the corner radius, which item starts selected, the colour of the current indicator and the colour of the dots. Everything is optional with a default, which means a drawer can be constructed with no arguments at all, as the first example shows, and then configured afterwards.
The design is worth noting because it is the opposite of a configuration-heavy component. There is no animation timing parameter, no spring configuration, and no way to customise the curve of the transition, even though several of these effects are explicitly animated. You get the effect as the library author designed it, or you write your own drawer.
Two ways to drive the indicator from a scroll view
The integration story is short and has one real decision in it. You pass the scroll offset and the collection view width to the page control, and there are two ways to do it.
The first uses the fractional offset directly:
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let offSet = scrollView.contentOffset.x
let width = scrollView.frame.width
pageControl.setPageOffset(offSet/width)
// OR
let index = Int(round(offSet/width))
pageControl.setPage(index) // This will animate the page controll transition, whenever the index is changed, no need to pass an offset of every scroll offset
}The distinction is the interesting part. setPageOffset takes a fractional value, so the indicator can sit between two positions while the user is dragging, which is what makes the worm and scrolling effects feel attached to the content rather than snapping at the end of a swipe. setPage takes an integer index and, as the comment in the README notes, animates the transition whenever the index changes, so you do not need to pass an offset on every scroll event.
The two behave differently mid-gesture, and that is the practical decision. With the offset version, a slow drag moves the indicator gradually. With the index version, the indicator sits still and then animates once the rounded index changes, which is the conventional page control behaviour and the cheaper option.
Either way, the wiring is one method on your view controller, called from scrollViewDidScroll, and the index is derived from the offset divided by the width. That division assumes one item fills the collection view width, which is the setup the README describes.
The UICollectionView setup the library assumes
The library does not include a container view of its own. The documented usage starts from a collection view you already have, and the README describes the setup in plain terms: create a collection view, link the data source and delegate to the view controller, and add UICollectionViewDelegateFlowLayout.
The example view controller conforms to all three protocols:
class ViewController: UIViewController,
UICollectionViewDataSource,
UICollectionViewDelegate,
UICollectionViewDelegateFlowLayout { ....The collection view methods that follow are minimal. numberOfSections returns 5, numberOfItemsInSection returns 1, and cellForItemAt dequeues a reusable cell with the identifier cell. The layout method is the one that matters:
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: collectionView.frame.width, height: 250) // This is to restric the item width and heigth to achive the single item preview
}The comment explains the intent, that this restricts the item width and height to achieve a single item preview. So the pattern is a horizontally paging collection view with one full-width item per section, five sections in the example, which gives the page control five pages to represent.
Two settings are then required in the storyboard: Scrolling enabled and Paging enabled in the collection view properties. Paging is what makes the offset division by width line up with a page index, and it is easy to miss, because without it the indicator will not track the pages correctly even though the code looks right.
Installing through CocoaPods and running the Example
AdvancedPageControl is available through CocoaPods, and the installation is the standard single line in a Podfile:
pod 'AdvancedPageControl'The repository also ships a Package.swift and a .swiftpm directory, so Swift Package Manager is supported as well, and the podspec is what the CocoaPods badge points at.
To see the effects, the README says to clone the repo and run pod install from the Example directory first. That is worth doing before anything else, because the entire value of this library is visual. The Example directory contains its own xcodeproj, xcworkspace, a Podfile and a Podfile.lock, plus a demo gif that shows the effects in sequence. The example project is a collection view with five sections and the drawers you assign, so it is the fastest way to see which of the thirteen effects suits your design.
The Project layout also explains something about the project history. There is a _Pods.xcodeproj at the top level and a .travis.yml, which is continuous integration configuration from the Travis era, alongside the modern .github/ directory. The repository is not archived, the last push was on 2026-04-16, and the two most recent releases are 0.11.0 and 0.10.0, both on 2026-04-16, minutes apart. A version 0.x library with two releases on the same day is a project at a pre-1.0 stage where the API may still move, so pin the version in your Podfile rather than tracking the branch.
Where AdvancedPageControl is the wrong tool
The first case is a SwiftUI app. The entire documented usage is UIKit: a UIViewController, a UICollectionView, delegate flow layout, storyboard checkboxes for scrolling and paging. There is no SwiftUI wrapper described anywhere in the documentation, and while a UIViewRepresentable could be written, that is your work, and the animation quality depends on how carefully you bridge the offset.
The second case is a simple indicator. If you need a row of dots that changes the highlighted one, UIPageControl does it with no dependency, no pod install and no drawer to choose. The trade for a library is real but narrow: you get thirteen looks instead of one, and you take on a dependency, a version to track and a 0.x API surface in exchange.
The third case is an app that needs more than the indicator. There is no accessibility configuration described, no way to make the control a proper accessibility element for VoiceOver, and no mention of dark mode adaptation. The colours are set directly on the drawer, which means adapting to a system appearance change is manual work on your side, and the default indicatorColor of .red and dotsColor of .lightGray are hard-coded light mode choices.
The alternative worth comparing is building the indicator as a small custom view inside your own app, drawing the dots in draw(_:) and animating a position with UIViewPropertyAnimator or a CADisplayLink timer. The difference in approach is ownership. A custom view gives you exact control over timing curves, dynamic type, VoiceOver support and dark mode, and it costs you an afternoon and a file in your project. AdvancedPageControl gives you thirteen polished effects immediately, and you inherit a design fixed by someone else's taste, including a set of timing curves you cannot adjust.
Editorial conclusion
AdvancedPageControl is the right choice for a UIKit team that wants a page indicator with more character than UIPageControl provides, since each effect is a separate drawer you can swap and the setPageOffset API lets the indicator track a paging scroll view without manual index bookkeeping. It is the wrong choice for a SwiftUI project, since the documented usage is entirely UIKit and UICollectionView, and for an app that needs a single standard dot indicator, where the framework component is enough. Before adopting it, run the Example project after pod install to see the effects at real size, confirm your deployment target matches the podspec and Package.swift, and decide whether you will drive the indicator by scroll offset or by rounded page index, since the two behave differently during a slow drag.
Frequently asked questions
How do I install AdvancedPageControl?
The library is available through CocoaPods by adding pod 'AdvancedPageControl' to your Podfile. The repository also ships a Package.swift and a .swiftpm directory for Swift Package Manager, and the podspec is published on CocoaPods.
Which page indicator effects does AdvancedPageControl provide?
The listed effects are Color Blend, Drop, ExtendedDot, Jump, Scale, Slide, Swap, Worm, ThinWorm, ThinWormHead, Scrolling and Infinite, each implemented as a drawer class such as ColorBlendDrawer or WormDrawer.
How do I sync the AdvancedPageControl indicator with a scrolling collection view?
In scrollViewDidScroll, pass the content offset divided by the collection view width to setPageOffset for a continuous indicator, or round that value to an index and pass it to setPage, which animates the transition when the index changes and does not need an offset on every scroll event.
How do I configure the size and colours of an AdvancedPageControl drawer?
Each drawer takes the same optional parameters, numberOfPages, height, width, space, radius, currentItem, indicatorColor and dotsColor, with defaults of 5 pages, 16 for the size values, 0 for currentItem, .red for the indicator and .lightGray for the dots.
What licence is AdvancedPageControl released under?
The library is MIT licensed, with the licence text in the LICENSE file at the repository root. The repository is not archived and the last push was on 2026-04-16, the same day as the 0.11.0 and 0.10.0 releases.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/mohn93-advancedpagecontrol)Was this useful?