在创建APP的基本框架的时候,最开始搭建的就是导航栏,然后往里塞东西,所以在创建导航栏时,有多种方式。

1、BottomNavigationBar + ViewPager + Fragment

这种方式 在之前项目中有介绍过,所以可以去翻之前的博客,这里就不再赘述。

2、BottomNavigationView + Fragment

这是JectPack组件出现之后,常用的一种导航栏模式,涉及到Navigation的用法,在之前的《JectPack组件开发3-----Navigation的用法》提及到。

首先在使用BottomNavigationView之前,先做一些准备工作。

(1)创建navigation文件

harmonyos 导航栏封装 导航栏实现_Group


(2)创建menu菜单

menu菜单作为底部导航栏的资源。

<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/first"
        android:title="第一个"
        android:icon="@drawable/ic_airline_seat_flat_angled_black_24dp"></item>
    <item android:id="@+id/second"
        android:title="第二个"
        android:icon="@drawable/ic_airline_seat_flat_angled_black_24dp"></item>
    <item android:id="@+id/third"
        android:title="第三个"
        android:icon="@drawable/ic_airline_seat_flat_angled_black_24dp"></item>
</menu>

(3)添加BottomNavigationView组件

需要设置底部导航的资源,并放到底部;左右点连接代表和父容器对齐,高度选择wrap_content。

harmonyos 导航栏封装 导航栏实现_android_02


harmonyos 导航栏封装 导航栏实现_android_03


(4)添加Fragment

harmonyos 导航栏封装 导航栏实现_ide_04


高度选择match_constraint显示就是0dp

harmonyos 导航栏封装 导航栏实现_ide_05


(5)设置导航

bottomNavigationView = findViewById(R.id.bottomNavigationView);
        NavController controller = Navigation.findNavController(this,R.id.fragment);

        //底部导航栏的配置
        AppBarConfiguration configuration = new AppBarConfiguration.Builder(controller.getGraph()).build();
        //这种方式不会有back的按键
        AppBarConfiguration configuration = new AppBarConfiguration.Builder(bottomNavigationView.getMenu()).build();
        NavigationUI.setupActionBarWithNavController(this,controller,configuration);
        NavigationUI.setupWithNavController(bottomNavigationView,controller);

要注意的一点是:menu中每个Item的id一定要和每个Fragment的id一致,否则导航无法生效。

3、原始的RadioGruop + FrameLayout

在使用这种导航形式时,就需要使用Fragment事务管理,将Fragment添加到FrameLayout中显示。

private int currentIndex = 0;
    private Fragment[] fragments;
 FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();

        firstFragment = new FirstFragment();
        secondFragment = new SecondFragment();
        thirdFragment = new ThirdFragment();

        fragments = new Fragment[]{firstFragment,secondFragment,thirdFragment};
        //把首页添加进去
        transaction.add(R.id.fl_main,firstFragment).commit();
        //默认选中第一个
        select(currentIndex);
private void select(int index) {
        if(currentIndex == index){
            return;
        }
        //隐藏当前的Fragment
        FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
        ft.hide(fragments[currentIndex]);

        if(!fragments[index].isAdded()){
            ft.add(R.id.fl_main,fragments[index]);
        }else{
            ft.show(fragments[index]);
        }
        ft.commit();
        currentIndex = index;
    }

然后RadioGroup设置点击事件:

rg_main.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(RadioGroup group, int checkedId) {
                switch (checkedId){
                    case R.id.rb_first:
                        select(0);
                        break;
                    case R.id.rb_second:
                        select(1);
                        break;
                    case R.id.rb_third:
                        select(2);
                        break;
                }
            }
        });

在开启Frgament事务之后,通过调用add方法往容器中添加Fragment实例,显示在手机屏幕上,该方法需要在commit之后才会生效;同样需要commit的是replace,这种方法使用比较少,它是将容器中全部实例移除之后,在添加新的Fragment,因为Fragment不能重复添加,相当于执行remove之后再执行add,重新走一遍生命周期,所以也需要commit。

同一个事务只能被commit一次,commit方法是在装载Fragment容器的Activity调用onSaveInstanceState之前执行,因为onSaveInstanceState() 方法在 onStop() 方法之前执行,也是为了确保在Activity因为某些不可抗性导致进程被杀死,保存当前的状态;如果对Fragment的状态没有具体的要求,可以使用commitAllowingStateLoss()。

在实际的开发过程中,往往会使用add和hide或者show配合使用。Fragment的实例都在内存当中,只有当Fragment实例不存在时,才能添加Fragment到容器当中,所以当Fragment实例存在的时候,只需要调用show方法commit就可以显示Fragment;当需要隐藏该界面时,调用hide方法隐藏。


Fragment添加转场动画
(1)系统自带API

FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);

setTransition是需要在add或者remove之前调用,使用FragmentTransaction自带的一些动画。

(2)自定义View

@NonNull
    public FragmentTransaction setCustomAnimations(@AnimatorRes @AnimRes int enter,
            @AnimatorRes @AnimRes int exit) {
        return setCustomAnimations(enter, exit, 0, 0);
    }

通过设置setCustomAnimations包括进场和退出的动画