There are a few posts on getting ViewPager to work with varying height items that center around extending ViewPager
itself to modify its onMeasure
to support this.
However, given that ViewPager2
is marked as a final class, extending it isn't something that we can do.
Does anyone know if there's a way to make this work out?
View1 = 200dp
View2 = 300dp
When the ViewPager2 (layout_height="wrap_content"
) loads -- looking at View1, its height will be 200dp.
But when I scroll over to View2, the height is still 200dp; the last 100dp of View2 is cut off.
The solution is to register a PageChangeCallback
and adjust the LayoutParams
of the ViewPager2
after asking the child to re-measure itself.
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 }
}
}
}
})
Alternatively, if your view's height can change at some point due to e.g. asynchronous data load, then use a global layout listener instead:
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 }
}
}
}
}
See discussion here: