ViewPager2 improves on the previous ViewPager implementation:
-
FragmentTransactionCallback interface, is used to monitor changes occurred within FragmentStateAdapter fragments of life cycle
-
RTL (right-to-left) layout support
-
Vertical support
-
Reliable Fragment support (including handling changes to the underlying Fragment collection)
-
Animation of data set changes (including DiffUtil support)
-
ItemDecorator, which behaves the same as RecyclerView.
-
MarginPageTransformer, to provide the ability to create Spaces between pages (outside of page margins).
-
CompositePageTransformer to provide the ability to compose multiple PageTransformers
ViewPager2 samples github:
Github.com/android/vie…
In addition to horizontal paging, vertical paging is also supported, thanks to the recyclerView function of ViewPage2, which dynamically changes the Fragment collection and calls notifyDatasetChanged() to update the interface.
ViewPager, paging through a fixed number of fragments, use FragmentPagerAdapter, paging through a large number of fragments, use FragmentStateAdapter and ViewPager2 has only a FragmentStateAdapter
The getPageWidth() method for ViewPager2 is not supported. If you currently use getPageWidth() for ViewPager to quickly view adjacent pages, you must use the clipToPadding property of RecyclerView instead
Used with TAB:
<! -- A ViewPager2 element with a TabLayout -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.google.android.material.tabs.TabLayout
android:id="@+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
</LinearLayout>
Copy the code
TabLayoutMediator combines the two, similar to setupWithViewPager
val tabLayout = view.findViewById(R.id.tab_layout)
TabLayoutMediator(tabLayout, viewPager) { tab, position ->
tab.text = "OBJECT ${(position + 1)}"
}.attach()
Copy the code
In order to support the same ViewPager2 object within the scroll view direction, if you want to scroll nested elements, you must to ViewPager2 objects call requestDisallowInterceptTouchEvent (). The ViewPager2 nested scroll example shows an approach to this problem using a generic custom wrapper layout.
Github.com/android/vie…
/** * Layout to wrap a scrollable component inside a ViewPager2. Provided as a solution to the problem * where pages of ViewPager2 have nested scrollable elements that scroll in the same direction as * ViewPager2. The scrollable element needs to be the immediate and only child of this host layout. * * This solution has limitations when using multiple levels of nested scrollable elements * (e.g. a horizontal RecyclerView in a vertical RecyclerView in a horizontal ViewPager2). */
class NestedScrollableHost : FrameLayout {
constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
private var touchSlop = 0
private var initialX = 0f
private var initialY = 0f
private val parentViewPager: ViewPager2?
get() {
var v: View? = parent as? View
while(v ! =null && v !is ViewPager2) {
v = v.parent as? View
}
return v as? ViewPager2
}
private val child: View? get() = if (childCount > 0) getChildAt(0) else null
init {
touchSlop = ViewConfiguration.get(context).scaledTouchSlop
}
private fun canChildScroll(orientation: Int, delta: Float): Boolean {
val direction = -delta.sign.toInt()
return when (orientation) {
0-> child? .canScrollHorizontally(direction) ? :false
1-> child? .canScrollVertically(direction) ? :false
else -> throw IllegalArgumentException()
}
}
override fun onInterceptTouchEvent(e: MotionEvent): Boolean {
handleInterceptTouchEvent(e)
return super.onInterceptTouchEvent(e)
}
private fun handleInterceptTouchEvent(e: MotionEvent) {
valorientation = parentViewPager? .orientation ? :return
// Early return if child can't scroll in same direction as parent
if(! canChildScroll(orientation, -1f) && !canChildScroll(orientation, 1f)) {
return
}
if (e.action == MotionEvent.ACTION_DOWN) {
initialX = e.x
initialY = e.y
parent.requestDisallowInterceptTouchEvent(true)}else if (e.action == MotionEvent.ACTION_MOVE) {
val dx = e.x - initialX
val dy = e.y - initialY
val isVpHorizontal = orientation == ORIENTATION_HORIZONTAL
// assuming ViewPager2 touch-slop is 2x touch-slop of child
val scaledDx = dx.absoluteValue * if (isVpHorizontal) .5f else 1f
val scaledDy = dy.absoluteValue * if (isVpHorizontal) 1f else .5f
if (scaledDx > touchSlop || scaledDy > touchSlop) {
if (isVpHorizontal == (scaledDy > scaledDx)) {
// Gesture is perpendicular, allow all parents to intercept
parent.requestDisallowInterceptTouchEvent(false)}else {
// Gesture is parallel, query child if movement in that direction is possible
if (canChildScroll(orientation, if (isVpHorizontal) dx else dy)) {
// Child can scroll, disallow all parents to intercept
parent.requestDisallowInterceptTouchEvent(true)}else {
// Child cannot scroll, allow all parents to intercept
parent.requestDisallowInterceptTouchEvent(false)}}}}}}Copy the code
PageTransformer page transition animation
val rotateChecked = false
val translateCheckBoxChecked = true
val scaleCheckBoxChecked = true
val translateX = viewPager.orientation == ORIENTATION_VERTICAL &&
translateCheckBoxChecked
val translateY = viewPager.orientation == ORIENTATION_HORIZONTAL &&
translateCheckBoxChecked
val mAnimator = ViewPager2.PageTransformer { page, position ->
val absPos = Math.abs(position)
page.apply {
rotation = if (rotateChecked) position * 360 else 0f
translationY = if (translateY) absPos * 500f else 0f
translationX = if (translateX) absPos * 350f else 0f
if (scaleCheckBoxChecked) {
val scale = if (absPos > 1) 0F else 1 - absPos
scaleX = scale
scaleY = scale
} else {
scaleX = 1f
scaleY = 1f}}}// Combine effect
viewPager.setPageTransformer(CompositePageTransformer().also {
it.addTransformer(mAnimator)
it.addTransformer(MarginPageTransformer(50))})Copy the code