ViewPager2高度无法跟随fragment自适应问题

背景:ViewPager2下不同的tab会对应各自的fragment,往往这些fragment的高度是不同的,然而在允许预加载的条件下ViewPager2的高度会始终跟随最高的那个fragment的高度,这就会导致其他不够高的fragment出现留白的问题。即便禁止了预加载,只要点击tab加载了比当前fragment更高的另一个fragment那么viewPager的高度也会随着改变,就仍然会导致上一个fragment出现大量留白的问题。如下所示:

 思考:首先我们想要的效果是viewPager的高度始终和当前的fragment保持一致,那么就需要在每一次点击tab的时候重新计算当前fragment的高度并将高度设置给viewPager,代码如下:

...
    override fun createFragment(position: Int): Fragment {
        val fragment: Fragment = AFragment()
        fragmentList.add(position, fragment)//声明一个Fragment类型的集合来作为缓存区
        return fragment
    }
...

hotSpotsTabLayout?.setOnItemSelectListener(object :
    HotSpotsTabLayout.OnItemSelectListener {
        override fun onItemSelect(text: String?, index: Int) {
            binding.viewPager.currentItem = index
            updatePagerHeightForChild(fragmentList[index].view, binding.viewPager)
        }
})

//计算fragment的高度并设置给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
                }
        }
    }
}

如果当前viewPager禁止预加载,那么在你点击tab的时候onItemSelect方法会比createFragment方法更早的执行,这就意味着在onItemSelect方法中通过fragmentList[index].view去拿下一个Fragment是拿不到的,因为根本就还没有add进去甚至都还没有创建,然后就会报数组越界的问题。

如果允许预加载,上述的问题就不存在了,点击tab后viewPager的高度都可以跟着变化。但是,你会发现在不点击任意tab的时候展示的第一个fragment的高度也会留白(除非第一个fragment碰巧就是最高的那个),只有点击其他tab再点回来它的高度才会自适应。这是因为允许预加载之后viewPager在加载完成时它的高度仍然跟随最高的那个fragment,点击tab重新计算高度的逻辑并没有走。那么在createFragment方法中也调用一次updatePagerHeightForChild方法呢?这样是无效的,因为fragment并没有完成绘制,还不在viewTree中,即便fragment已经创建你拿到的fragmentList[index].view仍然是null值,有兴趣的小伙伴可以试试。

解决:所以我们需要在一个可以监听到viewPager初始化同时又可以监听到viewPager点击tab进行切换的地方调用updatePagerHeightForChild方法,能立刻想到的就是用ViewTreeObserver去注册viewPager的OnGlobalLayoutListener监听,你会发现viewPager初始化以及切换tab的时候都会触发这个监听,不管是否禁止了预加载都不会有影响:

binding.viewPager.viewTreeObserver.addOnGlobalLayoutListener {
    updatePagerHeightForChild(fragmentList[binding.viewPager.currentItem].view, binding.viewPager)
}

问题完美解决~

  • 10
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我们间的空白格

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值