ViewPager2 具有不同的项目高度和 WRAP_CONTENT

Mep*_*ros 21 android android-viewpager2

有一些关于让 ViewPager 使用不同高度的项目的帖子,这些项目以扩展ViewPager自身为中心,以修改其onMeasure以支持这一点。

然而,鉴于它ViewPager2被标记为 final 类,扩展它不是我们可以做的事情。

有谁知道是否有办法解决这个问题?


例如,假设我有两种观点:

视图 1 = 200dp

视图 2 = 300dp

当 ViewPager2 (layout_height="wrap_content" ) 加载时——查看 View1,它的高度将为 200dp。

但是当我滚动到View2时,高度仍然是200dp;View2 的最后 100dp 被截断。

Vic*_*tor 28

只需为所需的Fragment内容执行此操作即可ViewPager2

override fun onResume() {
     super.onResume()
     layoutTaskMenu.requestLayout()
}
Run Code Online (Sandbox Code Playgroud)

Jetpack:(binding.root.requestLayout()感谢@syed-zeeshan 提供详细信息)

  • 这工作得很好..我刚刚在 onResume 中调用了它“binding.root.requestLayout()” (3认同)

Mep*_*ros 15

解决的办法是注册PageChangeCallback和调整LayoutParamsViewPager2要求儿童重新衡量自身后。

pager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
    override fun onPageSelected(position: Int) {
        super.onPageSelected(position)
        val view = // ... get the view
        view.post {
            val wMeasureSpec = MeasureSpec.makeMeasureSpec(view.width, MeasureSpec.EXACTLY)
            val hMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)
            view.measure(wMeasureSpec, hMeasureSpec)

            if (pager.layoutParams.height != view.measuredHeight) {
                // ParentViewGroup is, for example, LinearLayout
                // ... or whatever the parent of the ViewPager2 is
                pager.layoutParams = (pager.layoutParams as ParentViewGroup.LayoutParams)
                    .also { lp -> lp.height = view.measuredHeight }
            }
        }
    }
})
Run Code Online (Sandbox Code Playgroud)

或者,如果由于异步数据加载等原因,您的视图的高度可能会在某些时候发生变化,那么请改用全局布局侦听器:

pager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
    private val listener = ViewTreeObserver.OnGlobalLayoutListener {
        val view = // ... get the view
        updatePagerHeightForChild(view)
    }

    override fun onPageSelected(position: Int) {
        super.onPageSelected(position)
        val view = // ... get the view
        // ... IMPORTANT: remove the global layout listener from other views
        otherViews.forEach { it.viewTreeObserver.removeOnGlobalLayoutListener(layoutListener) }
        view.viewTreeObserver.addOnGlobalLayoutListener(layoutListener)
    }

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

            if (pager.layoutParams.height != view.measuredHeight) {
                // ParentViewGroup is, for example, LinearLayout
                // ... or whatever the parent of the ViewPager2 is
                pager.layoutParams = (pager.layoutParams as ParentViewGroup.LayoutParams)
                    .also { lp -> lp.height = view.measuredHeight }
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

请参阅此处的讨论:

https://issuetracker.google.com/u/0/issues/143095219

  • 你如何```// ...获取视图```? (10认同)
  • 如果我没有将任何项目传递给适配器,如何“// ...获取视图”?我正在使用 `FragmentStateAdapter` 并且在那里实例化片段。因为大小始终为 2,所以我仅使用静态值(2 表示“getItemCount”)。 (2认同)

小智 9

就我而言,添加adapter.notifyDataSetChanged()onPageSelected帮助。

  • 它工作得很晚..例如,我的第一个视图是300dp,第二个视图是200dp,第三个视图是200dp..当我从第一个视图转到第二个视图时,它仍然是300dp,直到我转到第三个视图..有什么解决方案吗? (2认同)

Adi*_*ane 6

只需在 ViewPager2 的所有片段中添加这个小代码

@Override
    public void onResume() {
        super.onResume();
        binding.getRoot().requestLayout();
    }
Run Code Online (Sandbox Code Playgroud)

这对我来说非常有用(如果您不使用绑定,那么只需获取根布局实例来代替绑定)


小智 5

然而,我自己偶然发现了这个案例。我决定将视图包装在 ConstraintLayout 中,而不是将视图调整为已接受的答案。这要求您指定 ViewPager2 的大小,而不是使用 wrap_content。

因此,与其改变我们的 viewpager 的大小,它必须是它处理的最大视图的最小大小。

对 Android 有点新,所以不知道这是否是一个好的解决方案,但它对我有用。

换句话说:

<androidx.constraintlayout.widget.ConstraintLayout
  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"
  >
    <!-- Adding transparency above your view due to wrap_content -->
    <androidx.constraintlayout.widget.ConstraintLayout
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      app:layout_constraintBottom_toBottomOf="parent"
      app:layout_constraintStart_toStartOf="parent"
      app:layout_constraintEnd_toEndOf="parent"
      >

      <!-- Your view here -->

    </androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
Run Code Online (Sandbox Code Playgroud)

  • 仅当您提前知道物品的高度时,这才有效。 (3认同)

小智 5

对我来说,这非常有效:


    viewPager2.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
            override fun onPageScrolled(
                position: Int,
                positionOffset: Float,
                positionOffsetPixels: Int
            ) {
                super.onPageScrolled(position,positionOffset,positionOffsetPixels)
                if (position>0 && positionOffset==0.0f && positionOffsetPixels==0){
                    viewPager2.layoutParams.height =
                        viewPager2.getChildAt(0).height
                }
            }
        })
Run Code Online (Sandbox Code Playgroud)