Sliding along; composing a dynamic reusable ViewPager Indicator Animator

Animations in mobile apps serve a multitude of purposes; from providing a way to delight users each time they interact with your app, to communicating a sense of direction and place within your app as a whole.
Focusing on the latter, swiping through views is a very popular UI/UX paradigm when there’s a list of content that can be paged through to the user. In Android, the ViewGroup
of choice for this pattern is usually the ViewPager
, and to a lesser extent a horizontal RecyclerView
, typically for content that doesn’t span the full screen or that takes a couple of rows. To communicate a user’s place within the list, indicators at the top or bottom of the scrolling view are commonly used, and there’s a wide variety of libraries that cover this functionality extremely well.
These libraries often provide their implementations via custom Views
and while this is a perfectly valid route to take, I’m a bit persnickety about what type of behavior should be in a custom view, and what should be delegated to a utility class. Furthermore, custom views don’t tend to have their implementation details and APIs easily accessible for tweaking and custom behavior, which can be rather restricting. With that said, how about we try composing the behavior we want to achieve into a utility class that easily exposes the API without having to create a custom view?
Step in the ViewPagerIndicatorAnimator
! As the name suggests, it is a composed Java class whose sole purpose is to create and animate indicators for a ViewPager
. You pass in arguments for the ViewPager
, the ConstraintLayout
it’s housed in, and a guideView
that dictates the ultimate position of the indicator. The API is fairly succinct:
With that declaration, we have a basic indicator that slides along, tracking the position of the user’s finger on the screen.
That alone may be a bit boring though, what if we want a little more fun? A little more pizzaz, some more pep in our step? Fortunately, since all the indicator is really doing behind the scenes is creating and adding dynamic ImageViews
, it’s easy to latch on to any instance of said ImageView
and animate them to our heart’s content. The ViewPagerIndicatorAnimator
exposes methods to retrieve the indicator at any position, as well as listen for indicator movements via the following API:
And the karaoke-esque bouncing pupper in the gif above is achieved with a little bit of math:
That’s pretty much all there is to it! With more math and time, you could easily make the icons roll, pulse with life and color, whatever you wanted to really, they’re regular views. The only dependencies you’d need to add would be the androidx components, but you probably had those already 😊.
How does it work though?
Most of the implementation detail is via the View.OnGlobalLayoutListener
, ViewPager.OnPageChangeListener
, ViewPager.OnAdapterChangeListener
APIs.
The View.OnGlobalLayoutListener
is used for initialization after the guide View
has been measured and laid out, otherwise we run the risk of getting a width of 0 in guide.getWidth()
.
The ViewPager.OnPageChangeListener
is used to detect page scrolls and the direction of the scroll, wether it’s to the left or right. It also provides how much of the ViewPager
has been scrolled, which is used to set the exact translation of the Indicator View
to match the user’s movement 1 : 1. It is this information that is proxied to the IndicatorWatcher’
s who wish to add other attributes to the animation.
Finally the ViewPager.OnAdapterChangeListener
is used in case the ViewPager
delays setting its adapter, or switches out its adapter at a later point.
The Animator implementation can be seen in it’s entirety below:
The full source for the ViewPagerIndicator
animator and demo project that generated the gif above can be gleaned from my Android Bootstrap repository linked below. The readme is still a bit sparse, and I’ll update it soon, but the view
module contains the ViewPagerIndicatorAnimator
and the app
module the sample code. If you’re fond of Shared Element Transitions in Android, you may want to dig around the source some more, however I do plan on writing more blog posts covering all parts of the sample app soon.
Thanks for reading, and a huge thanks to Lola Odelola for editing 😊.