实际开发中,经常会用到底部菜单的页面框架,今天我们就使用BottomNavigaitionView+Fragment组合实现。
废话不多说,直接码砖。。。
1、创建activity_bottomnavigationview_fragment.xml
bottom_menu.xml
2、创建4个Fragment页面FragmentTab1、FragmentTab2、FragmentTab3、FragmentTab4。这里以FragmentTab1为例:
public class FragmentTab1 extends BaseFragment {
@Override
protected int setContentView() {
return R.layout.fragment_item;
}
@Override
protected void findViewById(View rootView) {
TextView tv = (TextView) rootView.findViewById(R.id.id_fragment_content);
tv.setText("tab1");
}
}
关于BaseFragment和布局fragment_item.xml,请参考另外一篇文章ViewPager+Fragment懒加载
3、创建BottomNavigationViewFragmentActivity主页面;
public class BottomNavigationViewFragmentActivity extends AppCompatActivity {
private BottomNavigationView bottomNavigationView;
private Fragment mCurrentFragment = null;
private List fragments;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_bottomnavigationview_fragment);
bottomNavigationView = (BottomNavigationView) findViewById(R.id.id_bottom_menu);
bottomNavigationView.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_index:
showFragment(0);
return true;
case R.id.menu_video:
showFragment(1);
return true;
case R.id.menu_audio:
showFragment(2);
return true;
case R.id.menu_mine:
showFragment(3);
return true;
}
return false;
}
});
// 准备4个fragment页面
initFragment();
// 底部菜单默认选中第一个
bottomNavigationView.setSelectedItemId(bottomNavigationView.getMenu().getItem(0).getItemId());
}
private void initFragment() {
if (fragments != null) {
fragments.clear();
} else {
fragments = new ArrayList<>();
}
fragments.add(new FragmentTab1());
fragments.add(new FragmentTab2());
fragments.add(new FragmentTab3());
fragments.add(new FragmentTab4());
}
/**
* 使用show、hide来管理fragment
*/
private void showFragment(int position) {
if (fragments != null && fragments.size() > 0) {
Fragment fragment = fragments.get(position);
if (null != fragment && mCurrentFragment != fragment) {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
if (mCurrentFragment != null) {
transaction.hide(mCurrentFragment);
}
mCurrentFragment = fragment;
if (!fragment.isAdded()) {
transaction.add(R.id.fragment_item, fragment);
} else {
transaction.show(fragment);
}
transaction.commit();
}
}
}
}
ok,到此我们的页面就写完了。运行起来看看吧。
大功告成!
问题来了!!!
使用show()和hide()来管理fragment,在内存不足时,会出现重叠现象。我们改怎么做呢?接下来,我们先来复现这个问题,怎么做呢?
如何用真机模拟内存不足而杀死后台运行的activity呢?
如图所示,打开图片中的“不保留活动”选项即可;
再次运行我们刚才写的项目,点击菜单tab3,切换到tab3页面,然后按手机home键,返回主屏幕。此时,由于我们设置了不保留后台活动,我们的项目已经被kill掉了。然后再启动我们的应用
如图所示,我们fragment重叠了!!!
关于fragment重叠的原因和解决办法,网上有很多,大家可以自行选择,以下是我亲测有效的方式之一
上代码:
1、重写Activity的onSaveInstanceState()方法:
@Override
protected void onSaveInstanceState(Bundle outState) {
List fragments = getSupportFragmentManager().getFragments();
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
for (int i = 0; i < fragments.size(); i++) {
// 循环remove掉所有的fragment
transaction.remove(fragments.get(i));
}
transaction.commitAllowingStateLoss();
super.onSaveInstanceState(outState);
}
2、运行代码!!!
what? Fragment不重叠了,但是又有了新的问题,底部菜单在kill掉activity后,重新返回的时候,菜单状态还是kill掉之前的tab3,但是fragment却是tab1的,显然重新启动的时候onCreate()方法中的bottomNavigationView.setSelectedItemId(bottomNavigationView.getMenu().getItem(0).getItemId());么有起作用啊!
怎么办?
怎么办?
怎么办?
最终我的解决办法是这样的:
@Override
protected void onSaveInstanceState(Bundle outState) {
List fragments = getSupportFragmentManager().getFragments();
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
for (int i = 0; i < fragments.size(); i++) {
transaction.remove(fragments.get(i));
}
transaction.commitAllowingStateLoss();
super.onSaveInstanceState(outState);
// 重新设置BottomNavigationView的默认选中项
bottomNavigationView.setSelectedItemId(bottomNavigationView.getMenu().getItem(0).getItemId());
}
在onSaveInstanceState()中,添加bottomNavigationView.setSelectedItemId(bottomNavigationView.getMenu().getItem(0).getItemId());