【Android】ViewPager2切换fragment时高度无法自适应问题


前言

在这里插入图片描述
tab选项、底部或者顶部的导航栏、菜单栏 点击时都需要去切换fragment页面,可以有以下实现方式:

  1. 可以使用FrameLayout控件手动切换(不可滑动,滑动需单独实现)
  2. 使用viewpage2自动切换(可以滑动)

一、问题

ViewPage2是Jetpack中的其中一个组件,可以实现滑动切换页面的效果,通常可以搭配其他组件实现滑动切换效果。ViewPager2是基于RecyclerView实现的,自然继承了RecyclerView的众多优点,并且针对ViewPager存在的问题做了优化。可以使用offscreenPageLimi属性来预先加载页面,也可设置为0实现懒加载(页面显示时再加载)。
在这里插入图片描述

但是在实际开发中遇到一个问题:

ViewPager2下多个fragment的页面高度可能是不同的,在允许预加载的条件下ViewPager2的高度会始终跟随最高的那个fragment的高度,导致其他比较低的fragment页面出现留白的问题。即便禁止了预加载,也不能解决。

二、解决

1. ViewPage2添加配置

如果要实现ViewPage2的高度始终和当前的fragment保持一致,那么就需要在每一次点击tab的时候重新计算当前fragment的高度并将高度设置给ViewPage2。

vp2_frag是ViewPage2控件,fragmentList是所有fragment的集合

			private val fragmentList = arrayListOf<Fragment>()
			
			......
			
			//viewPager初始化以及切换tab的时候都会触发这个监听,不管是否禁止了预加载都不会有影响
            vp2_frag.viewTreeObserver.addOnGlobalLayoutListener {
                if(fragmentList.size>0){
                    updatePagerHeightForChild(fragmentList[vp2_frag.currentItem].view, vp2_frag)
                }
            }
            
            vp2_frag.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback(){
                override fun onPageSelected(position: Int) {
                    //切换页面效果
                    super.onPageSelected(position)
                    updatePagerHeightForChild(fragmentList[vp2_frag.currentItem].view, vp2_frag)
                }
            })
            
	//自适应高度,计算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
                }
            }
        }
    }

不允许预加载时,点击tab的时候onItemSelect方法可能会比创建Fragment更早的执行,导致拿不到fragment。

允许预加载之后,ViewPage2加载完成后它的高度仍然跟随最高的那个fragment,点击tab重新计算高度的代码没有执行,从而导致第一个fragment可能留白。

所以需要在一个可以监听到ViewPage2初始化又可以监听到ViewPage2切换的地方调用updatePagerHeightForChild方法。

2. 换成手动切换

使用FrameLayout去手动切换,重新加载页面:

<FrameLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_marginBottom="0dp"/>

在activity中使用:R.id.content是FrameLayout

在这里插入图片描述

好的,下面是实现步骤: 1. 首先在布局文件中添加TabLayout和ViewPager2控件,如下所示: ```xml <com.google.android.material.tabs.TabLayout android:id="@+id/tab_layout" android:layout_width="match_parent" android:layout_height="wrap_content" app:tabGravity="fill" app:tabMode="fixed"/> <androidx.viewpager2.widget.ViewPager2 android:id="@+id/view_pager" android:layout_width="match_parent" android:layout_height="match_parent"/> ``` 2. 在java文件中实例化TabLayout和ViewPager2控件,并设置ViewPager2的适配器,如下所示: ```java TabLayout tabLayout = findViewById(R.id.tab_layout); ViewPager2 viewPager = findViewById(R.id.view_pager); // 设置ViewPager2的适配器 viewPager.setAdapter(new MyFragmentPagerAdapter(this)); ``` 3. 创建FragmentPagerAdapter类,并实现getItemCount()和createFragment()方法,如下所示: ```java public class MyFragmentPagerAdapter extends FragmentPagerAdapter { private Context mContext; public MyFragmentPagerAdapter(Context context) { super(context); mContext = context; } @NonNull @Override public Fragment getItem(int position) { // 根据位置返回不同的Fragment switch (position) { case 0: return new Fragment1(); case 1: return new Fragment2(); case 2: return new Fragment3(); default: return new Fragment1(); } } @Override public int getItemCount() { return 3; // 返回Fragment的数量 } } ``` 4. 在java文件中为TabLayout添加Tab选项,并设置TabLayout的监听器,如下所示: ```java // 添加Tab选项 tabLayout.addTab(tabLayout.newTab().setText("Tab1")); tabLayout.addTab(tabLayout.newTab().setText("Tab2")); tabLayout.addTab(tabLayout.newTab().setText("Tab3")); // 设置TabLayout的监听器 tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() { @Override public void onTabSelected(TabLayout.Tab tab) { // 当Tab被选中切换ViewPager2对应的页面 viewPager.setCurrentItem(tab.getPosition()); } @Override public void onTabUnselected(TabLayout.Tab tab) { } @Override public void onTabReselected(TabLayout.Tab tab) { } }); ``` 5. 最后,在Fragment中添加自己的UI布局和逻辑代码即可。 以上就是使用TabLayout和ViewPager2实现Fragment界面切换的步骤,希望能对你有所帮助。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

full courage

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

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

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

打赏作者

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

抵扣说明:

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

余额充值