Search code examples
androidandroid-recyclerviewandroid-coordinatorlayoutandroid-viewpager2

ViewPager2 has wrong size when using with AppBarLayout and collapsing toolbar


I have this layout:

<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout
   xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:app="http://schemas.android.com/apk/res-auto"
   xmlns:tools="http://schemas.android.com/tools"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   android:fitsSystemWindows="true"
   tools:context=".MainActivity">

<com.google.android.material.appbar.AppBarLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:theme="@style/OfferingsMaterialTheme.AppBarOverlay"
    android:fitsSystemWindows="true">

    <androidx.appcompat.widget.Toolbar
      android:id="@+id/toolbar"
      app:layout_scrollFlags="scroll|enterAlways"
      android:layout_width="match_parent"
      android:layout_height="?android:attr/actionBarSize"
      android:background="?android:attr/colorPrimary"
      app:titleTextColor="@color/icons"
      app:title="@string/offeringsfragment_title"
      app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />

    <com.google.android.material.tabs.TabLayout
        android:id="@+id/tabs"
        style="@style/Widget.MaterialComponents.TabLayout.Colored"
        app:tabMaxWidth="0dp"
        app:tabGravity="fill"
        app:tabMode="fixed"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
</com.google.android.material.appbar.AppBarLayout>

<androidx.viewpager2.widget.ViewPager2
    android:id="@+id/viewpager"
    app:layout_anchorGravity="bottom"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

</androidx.coordinatorlayout.widget.CoordinatorLayout>

I am using app:layout_scrollFlags="scroll|enterAlways" in my ToolBar so it gets collapsed once the user scrolls up (there is a RecyclerView inside the ViewPager2). The problem is, the bottom part of the view in ViewPager2 is not visible. The height seems to get calculated wrongly. See this:

enter image description here

In the red part you can see that ViewPager2 expands over the size of the screen. I read many posts about it but could not find a solution for ViewPager2. Among others, I tried to wrap it inside a LinearLayout, but then the toolbar is not collapsing anymore. Any ideas?


Solution

  • For anyone who has the same problem: ViewPager2 seems to have a bug in calculating the right height. The only solution that worked for me is this. Here, we do this:

    The solution I found to this issue involves 2 parts.

    1. Add padding equal to the height of the AppBarLayout to the BOTTOM of the NestedScrollView. In my case because the AppBarLayout only contained a Toolbar, the height was ?attr/actionBarSize.
      android:paddingBottom="?attr/actionBarSize"

    2. Adding a custom AppBarLayout.OnOffsetChangedListener to the AppBarLayout which changes the height of the NestedScrollView as the toolbar is collapsed.

       class ScrollingOffsetFixListener(
           private val nestedScrollView: NestedScrollView
       ): AppBarLayout.OnOffsetChangedListener {
      
       private var originalHeight = 0
       private var firstOffset = true
      
       override fun onOffsetChanged(layout: AppBarLayout?, offset: Int) {
           if(firstOffset) {
               firstOffset = false
               originalHeight = nestedScrollView.measuredHeight
           }
      
           val params = nestedScrollView.layoutParams
           params.height = originalHeight + (offset * -1)
      
           nestedScrollView.layoutParams = params
          }
       }