Hack showcase: WheelPager
February 26, 2019
What?
This demo shows how to create a wheel-like page transformation for ViewPager2
(that supports both vertical & horizontal page transition).
Vertical | Horizontal |
---|---|
![]() |
![]() |
(If the gifs don’t show up, please check out this YouTube video for a demo)
How?
The key is to implement a PageTransformer
which makes the page items rotating around a pivot point like below:
viewPager.setPageTransformer { page: View, position: Float ->
page.apply {
// To allow only rotation around the pivot point.
x = 0f
y = 0f
// To adjust pivot point correctly based on ViewPager orientation.
when {
viewPager.orientation == ViewPager2.ORIENTATION_HORIZONTAL -> {
pivotX = width.toFloat() / 2f
pivotY = height.toFloat()
}
viewPager.orientation == ViewPager2.ORIENTATION_VERTICAL -> {
pivotX = width.toFloat()
pivotY = height.toFloat() / 2f
}
}
val direction = when {
viewPager.orientation == ViewPager2.ORIENTATION_HORIZONTAL -> 1f
viewPager.orientation == ViewPager2.ORIENTATION_VERTICAL -> -1f
else -> error("Oops! Sorry, this only works for vertical & horizontal.")
}
when {
position == 0f -> {
// When the page is front-and-center.
Log.i(logTag, "${page.tag} is now a front-and-center page")
rotation = direction * position * 180
}
position == 1f -> {
// When the page is a full page to the right (or bottom in vertical orientation).
Log.i(logTag, "${page.tag} is now a full page to the right")
rotation = direction * position * 180
}
position == -1f -> {
// When the page is a full page to the left (or up in vertical orientation).
Log.i(logTag, "${page.tag} is now a full page to the left")
rotation = direction * position * 180
}
position < 0 && position > -1f -> {
// [-1, 0]
// This is when moving a page in the LHS.
Log.i(logTag, "${page.tag} is moving w/ position $position")
rotation = direction * position * 180
}
position < 1 && position > 0f -> {
// (0, 1]
// This is when moving a page in the RHS.
Log.i(logTag, "${page.tag} is moving w/ position $position")
rotation = direction * position * 180
}
else -> {
// This is when `position` is out of the bounds of `[-1, 1]`.
// In other words, when the page is way off-screen.
Log.i(logTag, "${page.tag} is way off-screen")
}
}
}
}
Written by Thuy Trinh who lives and works in Frankfurt, Germany building robust Android apps. You should follow him on Twitter