15

这个问题是针对新的ViewPager2类的。

旧的 ViewPager也有类似的问题,但解决方案需要扩展ViewPager。但是, ViewPager2 是最终版本,因此无法扩展。

在我的情况下,我有一个包含三个不同片段的 ViewPager2。其中一个片段比其他两个片段高得多,这意味着当您滑动到其中一个较短的片段时,会有很多空白空间。那么如何有效地将 ViewPager2 包裹到当前片段的高度呢?

4

10 回答 10

13

解决方案是在作为一部分的每个片段中添加以下内容ViewPager2

override fun onResume() {
   super.onResume()
   binding.root.requestLayout()
}

binding.root来自 ViewBinding/DataBinding 但它是布局的主要容器,即ConstraintLayout,LinearLayout等。

于 2020-11-18T17:02:31.250 回答
7

我对这种解决方法一点也不满意,但它确实解决了我在尝试将 ViewPager2 与不同高度的片段一起使用时遇到的渲染问题。它显然会减慢渲染速度并消耗更多内存。

myStupidViewPager2.offscreenPageLimit = fragments.size
于 2019-11-10T14:03:42.010 回答
2

我有同样的问题,ViewPager2 在 ScrollView 中,它位于 TabLayout 下。浏览选项卡后,ScrollView 的高度等于最大片段高度的高度。通过将 ScrollView 转移到片段解决了该问题。

于 2020-05-01T16:38:35.863 回答
2

我找到了这个问题的答案,我通过它的适配器访问孩子,因为当您在任何给定位置访问孩子而不是 Zer0 索引时,视图为空。

    class ViewPager2PageChangeCallback() : ViewPager2.OnPageChangeCallback() {
        override fun onPageSelected(position: Int) {
            val view = (pager.adapter as pagerAdapter).getViewAtPosition(position)
            view?.let {
                updatePagerHeightForChild(view, pager)
            }
        }
    }

    private fun updatePagerHeightForChild(view: View, pager: ViewPager2) {
        view.post {
            val wMeasureSpec =
                View.MeasureSpec.makeMeasureSpec(view.width, View.MeasureSpec.EXACTLY)
            val hMeasureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
            view.measure(wMeasureSpec, hMeasureSpec)

            if (pager.layoutParams.height != view.measuredHeight) {
                pager.layoutParams = (pager.layoutParams)
                    .also { lp ->
                        lp.height = view.measuredHeight
                    }
            }
        }
    }

   pager.offscreenPageLimit = 1            
   pagerpager.registerOnPageChangeCallback(ViewPager2PageChangeCallback())

     override fun onDestroy() {
        super.onDestroy()
        pager.unregisterOnPageChangeCallback(ViewPager2PageChangeCallback())
    }

 

    class OrderDetailsPager(
    private val arrayList: ArrayList<Fragment>,
    fragmentManger: FragmentManager,
    lifecycle: Lifecycle
    ) : FragmentStateAdapter(fragmentManger, lifecycle) {
    override fun createFragment(position: Int): Fragment {
        return arrayList[position]
    }

    override fun getItemCount(): Int {
        return arrayList.size
    }

    fun getViewAtPosition(position: Int): View? {
        return arrayList[position].view
    }
}
于 2019-12-22T14:29:29.703 回答
1

我有一个动态页面高度的问题,它可能会在运行时发生变化。换页后,最高页的部分内容被截断。

我能够通过重新测量寻呼机内容(即页面)和寻呼机本身来解决这个问题。

         viewPager2.setPageTransformer { page, _ ->
                val wMeasureSpec =
                    View.MeasureSpec.makeMeasureSpec(page.width, View.MeasureSpec.EXACTLY)
                val hMeasureSpec =
                    View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
                page.measure(wMeasureSpec, hMeasureSpec)
                measure(wMeasureSpec, hMeasureSpec)
                post {
                    adapter?.notifyDataSetChanged()
                }
            }
于 2021-07-30T08:36:52.887 回答
1

花了很多时间后这对我有用,我viewpager2在里面Nesterscrollview

binding.viewpager.offscreenPageLimit = 2
binding.viewpager.isUserInputEnabled = false
binding.viewpager.registerOnPageChangeCallback(object :ViewPager2.OnPageChangeCallback(){
     override fun onPageSelected(position: Int) {
           super.onPageSelected(position)
           val myFragment = childFragmentManager.findFragmentByTag("f$position")
           myFragment?.view?.let { updatePagerHeightForChild(it,binding.viewpager) }
     }
})

private fun updatePagerHeightForChild(view: View, pager: ViewPager2) {
        view.post {
            val wMeasureSpec =
                View.MeasureSpec.makeMeasureSpec(view.width, View.MeasureSpec.EXACTLY)
            val hMeasureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
            view.measure(wMeasureSpec, hMeasureSpec)

            if (pager.layoutParams.height != view.measuredHeight) {
                pager.layoutParams = (pager.layoutParams)
                    .also { lp ->
                        lp.height = view.measuredHeight
                    }
            }
        }
    }
于 2021-03-12T07:55:03.103 回答
1

基于Lucas Nobile,我发现了另一种实现方式。而不是将以下代码放在每个受影响片段的 OnResume 方法上:

override fun onResume() {
   super.onResume()
   binding.root.requestLayout()
}

只需将此覆盖添加到 viewPager2 的适配器:

override fun onBindViewHolder(
   holder: FragmentViewHolder,
   position: Int,
   payloads: MutableList<Any>
){
   holder.itemView.requestLayout()
   super.onBindViewHolder(holder, position, payloads)
}

Obs:用 kotlin 编写的代码。

于 2021-09-30T15:55:13.840 回答
0

对我来说,set viewpager2 的 recyclerview 布局参数解决了这个问题。

尝试

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

并设置 recyclerview 布局参数

RecyclerView recyclerView = (RecyclerView) viewPager.getChildAt(0);
recyclerView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
于 2019-09-03T08:15:47.147 回答
0

我可以通过覆盖 onPageSelected 回调并重新测量当前视图的高度来做到这一点。

它看起来像这样:

mViewPager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
            @Override
            public void onPageSelected(int position) {
                mTabLayout.selectTab(mTabLayout.getTabAt(position));

 View view = mViewPagerAdapter.getViewAtPosition(position); // this is a method i have in the adapter that returns the fragment's view, by calling fragment.getview()
                if (view != null) {
                    view.post(() -> {
                        int wMeasureSpec = View.MeasureSpec.makeMeasureSpec(view.getWidth(), View.MeasureSpec.EXACTLY);
                        int hMeasureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
                        view.measure(wMeasureSpec, hMeasureSpec);
                        viewPager.getLayoutParams().height = view.getMeasuredHeight();
                        mViewPagerAdapter.notifyDataSetChanged();
                    });
                }
            }
        });
        mViewPager.setOffscreenPageLimit(mTabLayout.getTabCount());

TabLayout 和 Viewpager2 的布局如下所示(在 NestedScrollView 内)

<LinearLayout
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:orientation="vertical">

                        <com.google.android.material.tabs.TabLayout
                            android:id="@+id/data_collection_tab_layout"
                            android:layout_width="match_parent"
                            android:layout_marginBottom="12dp"
                            android:layout_height="wrap_content" />

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

                    </LinearLayout>

另外,请确保所有 Fragment 的布局高度都是包裹内容。

于 2021-04-24T20:07:33.893 回答
0

https://gist.github.com/safaorhan/1a541af729c7657426138d18b87d5bd4

这对我有用;

当我们想将 viewpager 用作 Book 页面时,感谢这项工作。有不同种类的页面高度。有时,当页面太长时,我们需要滚动操作:3 那时,只需用 NestedScroll View 包裹您的 viewpager 的项目布局。

感谢@safaorhan

/** * 禁用子附加侦听器,以便具有 wrap_content 高度的膨胀子可以通过。* * 这很脆弱,取决于[ViewPager2]的实现细节。* * @see ViewPager2.enforceChildFillListener(被移除的监听器)*/

// 用你的 viewpager 调用这个方法...

private fun ViewPager2.hackMatchParentCheckInViewPager() {
    (getChildAt(0) as RecyclerView).clearOnChildAttachStateChangeListeners()
}

//查看寻呼机

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

//您的子 Viewpager 项目

<androidx.core.widget.NestedScrollView
    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="wrap_content">

    <LinearLayout
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">
      ....
    </LinearLayout>
    </androidx.core.widget.NestedScrollView>
于 2021-02-02T04:56:18.977 回答