如何将Android ViewPager2的高度包装到当前项目的高度?

如何将Android ViewPager2的高度包装到当前项目的高度?,android,android-fragments,android-viewpager,android-viewpager2,Android,Android Fragments,Android Viewpager,Android Viewpager2,此问题适用于新的查看页面2类 存在一个,但解决方案需要扩展ViewPager。但是,ViewPager2是最终版本,因此无法扩展 在我的情况下,我有一个ViewPager2,它包含三个不同的片段。其中一个碎片比另外两个碎片高很多,这意味着当你滑动到其中一个较短的碎片时,会有很多空白。那么,如何有效地将ViewPager2包装到当前片段的高度呢?对于我来说,设置ViewPager2的recyclerview布局参数可以解决这个问题 试一试 我对这种解决方法一点也不满意,但它确实解决了我在尝试使用V

此问题适用于新的查看页面2

存在一个,但解决方案需要扩展ViewPager。但是,ViewPager2是最终版本,因此无法扩展


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

对于我来说,设置ViewPager2的recyclerview布局参数可以解决这个问题

试一试


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

myStupidViewPager2.offscreenPageLimit = fragments.size

我已经找到了这个问题的答案,我通过它的适配器访问子对象,就像在任何给定位置访问子对象而不是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
    }
}
类ViewPager2PageChangeCallback():ViewPager2.OnPageChangeCallback(){
覆盖所选页面(位置:Int){
val视图=(pager.adapter作为pagerAdapter)。getViewAtPosition(位置)
风景?让我看看{
updatePagerHeightForChild(视图、寻呼机)
}
}
}
private fun updatePagerHeightForChild(查看:查看,寻呼机:查看页面2){
view.post{
val wMeasureSpec=
View.MeasureSpec.makeMeasureSpec(View.width,View.MeasureSpec.justice)
val hMeasureSpec=View.MeasureSpec.makeMeasureSpec(0,View.MeasureSpec.UNSPECIFIED)
视图.度量(wMeasureSpec,hMeasureSpec)
if(pager.layoutParams.height!=视图.测量高度){
pager.layoutParams=(pager.layoutParams)
。同时{lp->
lp.height=视图测量高度
}
}
}
}
pager.offscreenPageLimit=1
pagerpager.registerOnPageChangeCallback(ViewPager2PageChangeCallback())
重写onDestroy(){
super.ondestory()
pager.unregisterOnPageChangeCallback(ViewPager2PageChangeCallback())
}
类OrderDetailsPage(
private val arrayList:arrayList,
碎片经理:碎片经理,
生命周期:生命周期
):FragmentStateAdapter(FragmentManager,生命周期){
重写片段(位置:Int):片段{
返回数组列表[位置]
}
重写getItemCount():Int{
返回arrayList.size
}
有趣的getViewAtPosition(位置:Int):查看{
返回arrayList[位置].视图
}
}

我也遇到了同样的问题,ViewPager2在ScrollView中,它位于TableLayout下。在通过选项卡导航后,ScrollView的高度等于最大片段高度的高度。
通过将ScrollView传输到片段解决了此问题。

解决方案是在属于
ViewPager2
的每个片段中添加以下内容:

override fun onResume() {
   super.onResume()
   binding.root.requestLayout()
}
binding.root
来自ViewBinding/DataBinding,但它是布局的主要容器,即
ConstraintLayout
LinearLayout
,等等。

这是我的工作

感谢这项工作为我,当我们想使用viewpager作为书的'页。有不同种类的页面高度。有时,当页面太长时,我们需要滚动操作:3此时,只需使用NestedScroll视图包装viewpager的项目布局

感谢@safaorhan

/** *禁用子附加侦听器,以便具有换行内容高度的充气子对象可以通过。 * *这非常脆弱,取决于[ViewPager2]的实现细节。 * *@请参阅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>

....

这对我来说很有效。在花了很多时间之后,我的
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) }
     }
})


我可以通过覆盖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的布局如下所示(在嵌套的ScrollView中)



另外,请确保所有片段的布局高度都是包装内容。

请发布代码和截图。你能理解吗?@Kimble还没有:-(另请参阅和。谢谢,但这对我不起作用。我所有的ViewPager2页面都随此代码一起消失了。也就是说,我的页面现在是视图(而不是片段),因此您的答案可能对其他人有用。
viewPager.setOffscreenPageLimit(3);
对我不起作用。但是,我的页面现在是视图(而不是片段),因此,您的答案可能对其他人有用。您实际在哪里调用此方法?好主意,但不处理延迟加载的项目(如分页)这不起作用,什么是getViewAtPosition和pagerAdapter?代码非常糟糕。getViewAtPosition作为在pagerAdapter(View pager2适配器)中添加的方法@AssemMahrous能否请您更新示例代码以同时显示getViewAtPosition和pagerAdapter,因为我对这些代码的来源感到困惑。我已经编辑了代码并添加了寻呼机适配器@Sphrake为什么您要在
onDestroy
pager.unregisterOnPageChangeCallback(ViewPager2PageChangeCallback)中再次创建回调())
?哈,这很有趣。你能解释一下这个代码到底是做什么的吗……它解决了我的问题,但我不明白为什么
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
                    }
            }
        }
    }
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());
<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>