如题,用bottomNavigateView和fragment做切换多是一件美事啊,可就是搞了半天都弄不出来还各种不对,今天就来分享一下我在这之中遇到的坑以及解决办法(当做笔记了):
前言
做页面切换市面上常用的方式有两种,一种是直接暴力替换,一种是显示和隐藏如下:
正文
方法一: 暴力替换
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//初始化(findViewById)
BottomNavigationView bav = findViewById(R.id.bottomNavigationView);
//设置监听
bav.setOnItemSelectedListener(new NavigationBarView.OnItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
//判断是哪个item被点击了
switch (item.getItemId()) {
case R.id.bottom_menu_home:
getSupportFragmentManager().beginTransaction().replace(R.id.fragment,new FragmentHome()).commit();
break;
case R.id.bottom_menu_found:
getSupportFragmentManager().beginTransaction().replace(R.id.fragment,new FragmentFind()).commit();
break;
case R.id.bottom_menu_message:
getSupportFragmentManager().beginTransaction().replace(R.id.fragment,new FragmentMessage()).commit();
break;
default:
getSupportFragmentManager().beginTransaction().replace(R.id.fragment,new FragmentMe()).commit();
break;
}
item.setChecked(true);
return false;
}
});
}
但是这种方法虽然简单粗暴但是每次点击底部的按钮切换页面时都会重新加载一遍fragment,这样很消耗性能同时也给用户带来不好的体验,举个简单的例子:比如用户在首页滚动到某一个位置,然后切换到我的页面看了一下,准备切回首页的时候发现刚才滚动到的位置没了,直接回到顶部了,那是因为fragment重新加载了一遍。为了解决这个问题,于是就出现下一种方案,用显示和隐藏来切换页面:
显示和隐藏来切换页面的思路无非就是,先初始化fragment(也就是把该new的fragment都new出来存放到Arraylist里面去方便后续操作),然后就是显示和隐藏fragment就行了,所以写三个方法分别是初始化,显示,隐藏,如下:
方法二: 显示和隐藏
初始化:
private void initFragment() {
//用一个叫fragments的Arraylist储存所有的fragment
fragments.add(getSupportFragmentManager().findFragmentByTag("f_home"));//找到主页的fragment(因为一开始显示的就是主页,所以直接在xml里面就初始化了)
fragments.add(new FragmentFind());//发现页面
fragments.add(new FragmentMessage());//消息页面
fragments.add(new FragmentMe());//我的页面
}
显示:
private void showFragment(int position) {
//加个判断防止报错
if (fragments.get(position).isAdded()) {
getSupportFragmentManager().beginTransaction().show(fragments.get(position)).commit();
} else {
//添加完成后自动显示,无需在操作
getSupportFragmentManager().beginTransaction().add(R.id.fragment, fragments.get(position)).commit();
}
}
隐藏:
private void hideFragment() {
//隐藏所有的页面
for (int i = 0; i < fragments.size(); i++) {
//加个判断防止报错
if (fragments.get(i).isAdded()) {
getSupportFragmentManager().beginTransaction().hide(fragments.get(i)).commit();
}
}
}
接下来的操作就是将上面暴力替换方式变成先隐藏后显示的方式就行了,代码如下:
//设置监听
bav.setOnItemSelectedListener(new NavigationBarView.OnItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
//隐藏掉所有的fragment
hideFragment();
//判断是哪个item被点击了
switch (item.getItemId()) {
case R.id.bottom_menu_home:
//getSupportFragmentManager().beginTransaction().replace(R.id.fragment,new FragmentHome()).commit();
showFragment(0);
break;
case R.id.bottom_menu_found:
//getSupportFragmentManager().beginTransaction().replace(R.id.fragment,new FragmentFind()).commit();
showFragment(1);
break;
case R.id.bottom_menu_message:
//getSupportFragmentManager().beginTransaction().replace(R.id.fragment,new FragmentMessage()).commit();
showFragment(2);
break;
default:
//getSupportFragmentManager().beginTransaction().replace(R.id.fragment,new FragmentMe()).commit();
showFragment(3);
break;
}
item.setChecked(true);
return false;
}
});
万事大吉,代码敲得啪啪响,非常顺利,但是,一运行起来就粗问题了,如图:
主页顺利展示出来了,点击发现页面就粗问题了,唉怎么啥都没有捏( ̄▽ ̄)*
并且不只是发现页面没有,其他页面也啥都没有,担心是代码逻辑出错了,或者是没有显示出来,或者是没有成功加载fragment,等等调试了半天发现一点问题都没有,为什么就是显示不出来呢???
经过半天的折腾我终于发现了其中的猫腻,原来主页是一个很特殊的fragment,特殊在哪里,特殊就特殊在它的显示和隐藏关乎所有fragment的显示和隐藏,一旦它被隐藏了那么其他的fragment也会被隐藏(有知道为什么的大佬可以说说),而显示发现页面必须要隐藏其他页面,不然就会出现重叠。所以首页这个fragment很特别,咱们惹不起,那就别惹了,回到xml里面将默认的fragment换成一个空的fragment,什么都没有就空白一片,以后咱们也不动它,既不会显示它也不会隐藏它,也不会替换它,只要让它好好的待着就行了。
PS:这里的空白的fragment就是充当了主页的位置,是一个很特殊的fragment,要默认显示主页只要在onCreate里面手动调用一次显示fragment的函数显示主页即可。
结语
好了问题解决了,不想忘记这次难忘的折腾,同时也想为各位避坑,因此做了此次笔记,大家就当笔记看就行了,也不是什么教程。