I have a ViewPager2
inside a BottomSheetDialog
in which I load a Fragment
that contains a ComposeView
. Inside this view I populate a LazyList
with items as soon as they're loaded.
Now this works all fine, except that the ViewPager2
makes no height adaptions when it's inner contents change, so naturally I adapted the peekHeight
at first and then added a GlobalLayoutListener
to give the pager the height of the inner, currently displayed fragment view, like so:
val myPager = ...
myPager.registerOnPageChangeCallback(AdaptChildHeightOnPageChange(myPager))
...
internal class AdaptChildHeightOnPageChange(private val viewPager: ViewPager2) : ViewPager2.OnPageChangeCallback() {
private val otherViews = mutableSetOf<View>()
private fun getViewAtPosition(position: Int): View =
(viewPager.getChildAt(0) as RecyclerView).layoutManager?.findViewByPosition(position)
?: error("No layout manager set or no view found at position $position")
override fun onPageSelected(position: Int) {
super.onPageSelected(position)
val itemView = getViewAtPosition(position)
val layoutListener = ViewTreeObserver.OnGlobalLayoutListener {
itemView.updatePagerHeightForChild()
}
// remove the global layout listener from other views
otherViews.forEach { it.viewTreeObserver.removeOnGlobalLayoutListener(it.tag as ViewTreeObserver.OnGlobalLayoutListener) }
itemView.viewTreeObserver.addOnGlobalLayoutListener(layoutListener)
itemView.tag = layoutListener
otherViews.add(itemView)
}
private fun View.updatePagerHeightForChild() {
post {
val wMeasureSpec = View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY)
val hMeasureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
measure(wMeasureSpec, hMeasureSpec)
if (viewPager.layoutParams.height != measuredHeight) {
viewPager.layoutParams = (viewPager.layoutParams as ViewGroup.LayoutParams)
.also { lp -> lp.height = measuredHeight }
}
}
}
}
(taken and adapted from https://stackoverflow.com/a/58632613/305532)
Now while this works fantastically with regular compose content, as soon as I switch my compose view to the LazyList
implementation (or anything that uses Modifier.verticalScroll(...)
), I receive the following exception:
Nesting scrollable in the same direction layouts like LazyColumn and \
Column(Modifier.verticalScroll()) is not allowed (Scroll.kt:370)
But I don't get this really, because I haven't nested any vertical-scolling compose elements that could trigger this exception. My only guess is that because of the height constraint I give to the ViewPager2
this internally triggers the enablement of vertical scrolling, making the inner LazyList
unable to take over.
How can I solve this issue?