Android Java项目中ViewPager2结合底部导航、抽屉布局时Fragment重叠问题咨询
问题根本原因
- 布局层级冲突:你当前布局中同时存在
ViewPager2和id为container的FrameLayout两个全屏Fragment承载容器,ViewPager2自带的Fragment和你手动添加到container的Fragment会直接叠加显示。 - 导航逻辑冲突:你为
BottomNavigationView配置了两套并行逻辑,一套是和ViewPager2联动的逻辑(仅初始化了ViewPager2和Adapter,未做联动),另一套是手动向container添加Fragment的逻辑,两个逻辑同时触发就会出现重叠。 - 回退栈冗余:每次切换底部导航Fragment都调用
addToBackStack(null),多次切换后回退栈会堆积大量Fragment实例,返回操作时也会出现重叠问题。 - 布局参数错误:你在
activity_main.xml中引入的drawer_toolbar和content_main高度都设为了wrap_content,两个全屏布局会互相覆盖。
修复步骤
第一步:统一Fragment承载方案,删除冗余布局
你同时使用了两种Fragment导航方案,二选一保留即可,推荐保留BottomNavigationView+ViewPager2的主流方案:
- 直接删除
activity_main.xml中对content_main的引入代码,以及content_main.xml的冗余FrameLayout容器,用ViewPager2统一承载所有底部导航Fragment。 - 调整
drawer_toolbar.xml的布局顺序和参数,避免BottomNavigationView遮挡ViewPager2内容:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <androidx.appcompat.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="#067B30" android:theme="@style/ThemeOverlay.AppCompat.Dark"> </androidx.appcompat.widget.Toolbar> <com.google.android.material.appbar.AppBarLayout android:layout_width="match_parent" android:layout_height="wrap_content" app:elevation="0dp"/> <androidx.viewpager2.widget.ViewPager2 android:id="@+id/vp_horizontal_ntb" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" app:layout_behavior="@string/appbar_scrolling_view_behavior" /> <com.google.android.material.bottomnavigation.BottomNavigationView android:id="@+id/navigation" app:menu="@menu/bottom_navigation" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="?android:attr/windowBackground" android:foreground="?attr/selectableItemBackground" /> </LinearLayout>
- 修改
activity_main.xml中drawer_toolbar的引入高度为占满全屏:
<include android:layout_width="match_parent" android:layout_height="match_parent" layout="@layout/drawer_toolbar"/>
第二步:修正BottomNavigationView和ViewPager2的联动逻辑
删除原来手动向container添加Fragment的逻辑,改为底部导航和ViewPager2双向联动:
private void initView() { viewPager2 = findViewById(R.id.vp_horizontal_ntb); // 仅2个页面,缓存1页足够 viewPager2.setOffscreenPageLimit(1); bottomNavigationView = findViewById(R.id.navigation); adapter = new ViewPagerAdapter(this); // 给Adapter添加底部导航对应的两个Fragment adapter.addFragment(new perfil_user()); adapter.addFragment(new genera_debate()); viewPager2.setAdapter(adapter); // 点击底部导航切换ViewPager2页面 bottomNavigationView.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() { @Override public boolean onNavigationItemSelected(@NonNull MenuItem item) { switch (item.getItemId()){ case R.id.perfil: viewPager2.setCurrentItem(0); break; case R.id.generar_debate: viewPager2.setCurrentItem(1); break; } return true; } }); // 滑动ViewPager2同步更新底部导航选中状态 viewPager2.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() { @Override public void onPageSelected(int position) { super.onPageSelected(position); bottomNavigationView.setSelectedItemId(position == 0 ? R.id.perfil : R.id.generar_debate); } }); }
第三步:修正抽屉导航跳转逻辑
如果抽屉的用户页和底部导航的用户页是同一个页面,直接切换ViewPager2位置即可,避免重复创建Fragment:
@Override public boolean onNavigationItemSelected(@NonNull MenuItem item) { if (item.getItemId() == R.id.user){ viewPager2.setCurrentItem(0); } else if (item.getItemId() == R.id.exit){ finish(); } drawerLayout.closeDrawer(GravityCompat.START); return true; }
第四步:确认ViewPagerAdapter实现正确
你的ViewPagerAdapter需要继承FragmentStateAdapter,参考实现如下:
public class ViewPagerAdapter extends FragmentStateAdapter { private final List<Fragment> fragmentList = new ArrayList<>(); public ViewPagerAdapter(@NonNull FragmentActivity fragmentActivity) { super(fragmentActivity); } public void addFragment(Fragment fragment) { fragmentList.add(fragment); } @NonNull @Override public Fragment createFragment(int position) { return fragmentList.get(position); } @Override public int getItemCount() { return fragmentList.size(); } }
内容的提问来源于stack exchange,提问作者Mauricio
相关产品推荐
相关产品推荐

