Pages must fill the whole ViewPager2 (use match_parent)

Viewed 32730

I have an item layout where I display an image, product name, and product image. I must display image in 1:1.5 ration using constraint layout. But when I load a small image, below texts not displaying.

Below is my code of item XML:-

<?xml version="1.0" encoding="utf-8"?>
<layout 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">

    <androidx.constraintlayout.widget.ConstraintLayout
        android:id="@+id/coordinatorLayoutCartRoot"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <com.jackandphantom.circularimageview.RoundedImage
            android:id="@+id/imageViewSlider"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:scaleType="centerCrop"
            app:layout_constraintBottom_toTopOf="@id/tvTitle"
            app:layout_constraintDimensionRatio="WH,1:1.4"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:rounded_radius="0"
            tools:src="@tools:sample/avatars" />

        <TextView
            android:id="@+id/tvTitle"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:padding="4dp"
            android:text="Fitted crew neck sweater"
            android:textColor="@color/colorBlack"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@id/imageViewSlider" />

        <TextView
            android:id="@+id/tvPrice"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:padding="4dp"
            android:text="$34.00"
            android:textColor="@color/colorBlack"
            android:textStyle="bold"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@id/tvTitle" />

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>
  1. Output with long image:- https://i.imgur.com/QVnljX6.png
  2. Output with small image:- https://i.imgur.com/0ZwkVwE.png

And if I replace match_parent with wrap_content, app crashes with below error :-

java.lang.IllegalStateException: Pages must fill the whole ViewPager2 (use match_parent)

22 Answers

I have found out that the problem is in inflating view holder.

I had the same issue and solved it changing

ViewBinding.inflate(inflater)

to

ViewBinding.inflate(inflater, parent, false)

While struggling with this problem, I figured it out what's the problem was. My use case was I was using androidx.viewpager2.widget.ViewPager2, and calling normal Views in RecyclerView.

If you notice the error carefully you would see something like this:

 java.lang.IllegalStateException: Pages must fill the whole ViewPager2 (use match_parent)
    at androidx.viewpager2.widget.ViewPager2$2.onChildViewAttachedToWindow(ViewPager2.java:170)

Second line is the key to main issue. If you open ViewPager2.java you would see

 private RecyclerView.OnChildAttachStateChangeListener enforceChildFillListener() {
    return new RecyclerView.OnChildAttachStateChangeListener() {
        @Override
        public void onChildViewAttachedToWindow(@NonNull View view) {
            RecyclerView.LayoutParams layoutParams =
                    (RecyclerView.LayoutParams) view.getLayoutParams();
            if (layoutParams.width != LayoutParams.MATCH_PARENT
                    || layoutParams.height != LayoutParams.MATCH_PARENT) {
                throw new IllegalStateException(
                        "Pages must fill the whole ViewPager2 (use match_parent)");
            }
        }

        @Override
        public void onChildViewDetachedFromWindow(@NonNull View view) {
            // nothing
        }
    };
}

Android is not taking the match_parent assigned in xml to attach views. May be future improvements would be done in next release of ViewPager2.

Anyways, for now to fix it, set layout params as MATCH_PARENT explicity.

 view.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));

This view is the parent view holding View Pager childs.

In you case it would be androidx.constraintlayout.widget.ConstraintLayout.

 view.setLayoutParams(new ConstraintLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));

set width and height in your adapter item of ViewPager2 match_parent

Use match_parent to your viewholder layout of ViewPager2

I have the same error, After sometimes I Found the issue in ViewPager2's adapter item, I changed it from wrap_content to match_parent, and it was Fixed.

<ImageView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/iv_banner"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/> <!--Change height here to match_parent-->

You should to write like this:

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
    val view: View = inflater.inflate(R.layout.yourlayout, parent, false)
    view.layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)
    return ViewHolder(view)
}
inner class ViewHolder(itemView: View) :
    RecyclerView.ViewHolder(itemView) {
}

For me, the issue was pages (i.e. parent/root layout of the adapter) in ViewPager2 were not match_parent hence the error was java.lang.IllegalStateException: Pages must fill the whole ViewPager2 (use match_parent)

viewpager2 item should have match_parent width and height. but IF you are using View Binding you should inflate layout such as fragments:

ViewBinding.inflate(inflater, parent, false)

i faced the same problem now , your adapter item width and height has to be match_parent

Possible scenario is also if you dont use parent in inflater. This crash with exception You have:

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): OnboardViewHolder {
        return OnboardViewHolder(parent.context.inflate(
                R.layout.view_onboard_item, null, false
        ))
    }

And this works :

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): OnboardViewHolder {
        return OnboardViewHolder(parent.context.inflate(
                R.layout.view_onboard_item, parent, false
        ))
    }

I had the same problem. I used ViewPager2 to display the slider. But its XML item was not MATCH_PARENT. After that change the problem was resolved.

I also faced the same issue, and the solution is to set the height as match_parent of your item view i.e layout used in adapter class must have height as MATCH_PARENT

set android:layout_width & android:layout_height to match_parent of ViewPager2 & adapter layout

I solve this by using wrap_content in parent view of ViewPager2

Example:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    tools:context=".presentation.home.view.BannerFragment">

    <androidx.viewpager2.widget.ViewPager2
        android:id="@+id/view_pager_banner"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

</LinearLayout>

So it will take the height of the adapter layout.

If you are using the viewpager2 inside the constraint layout just wrap viewpager2 with a relative layout:

<RelativeLayout
    android:id="@+id/sub_service_list_view_cont"
    android:layout_width="0dp"
    android:layout_height="0dp"
    app:layout_constraintBottom_toTopOf="@+id/basket"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toBottomOf="@+id/view14">

    <androidx.viewpager2.widget.ViewPager2
        android:id="@+id/sub_service_list_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</RelativeLayout>

I was facing this problem because my viewpager2 was in to a FragmentContainerView with layout_height="wrap_content".

So I changed it to: layout_height="match_parent" and solved the problem :)

I meet the error as you describe.

First,The problem occured in the recyclerview,so it's no matter with vipager2

Second,What is affected is recycleview's viewholder.

Last,Change the viewholder's width and height,make it is all match parent.

Good luck for you.

I also faced the same issue but when I change the item view height to match parent instead of wrap content it work fine.

for fixed error Pages must fill the whole ViewPager2 (use match_parent) :
Set enough height com.jackandphantom.circularimageview.RoundedImage to match_parent

android:layout_height="match_parent"

Viewpager2 by default forces the pages to be MATCH_PARENT, or an exception will be thrown

A solution for that is to do the following before you do anything to the viewpager. This will prevent the viewpager from throwing an exception when the page size is not MATCH_PARENT. Of course you must make your layout wrap_content in order for this to work.

((RecyclerView) yourViewPager2Object.getChildAt(0)).clearOnChildAttachStateChangeListeners();

Further Explanation.

if you go to the viewpager2 code you will find the following, and what we actually do is disabling this behavior.


    /**
     * A lot of places in code rely on an assumption that the page fills the whole ViewPager2.
     *
     * TODO(b/70666617) Allow page width different than width/height 100%/100%
     */
    private RecyclerView.OnChildAttachStateChangeListener enforceChildFillListener() {
        return new RecyclerView.OnChildAttachStateChangeListener() {
            @Override
            public void onChildViewAttachedToWindow(@NonNull View view) {
                RecyclerView.LayoutParams layoutParams =
                        (RecyclerView.LayoutParams) view.getLayoutParams();
                if (layoutParams.width != LayoutParams.MATCH_PARENT
                        || layoutParams.height != LayoutParams.MATCH_PARENT) {
                    throw new IllegalStateException(
                            "Pages must fill the whole ViewPager2 (use match_parent)");
                }
            }

            @Override
            public void onChildViewDetachedFromWindow(@NonNull View view) {
                // nothing
            }
        };
    }

Resources:

https://issuetracker.google.com/issues/70666617 https://gist.github.com/safaorhan/1a541af729c7657426138d18b87d5bd4

If you are using Data binding, try this on the Adapter class

override fun onCreateViewHolder(
    parent: ViewGroup,
    viewType: Int
): BannerViewHolder {
    return BannerViewHolder(
        HomeShopsBannerCellBinding.inflate(LayoutInflater.from(parent.context),
            parent,  //add this line
            false),  //add this line
        mListener,

    )
}

Also set Match parent for adapter cell layout and viewpager2 layout

I faced this problem and I fixed it just by replacing the

android:layout_height="wrap_content" of item of view pager adapter to android:layout_height="match_parent"

The layout_width and layout_height of adapter must be match_parent

Related