Android Jetpack Navigation组件(五):NavigationUI

一、前言

通过NavigationUI可以将导航组件与UI关联起来,在导航时自动更新UI。

二、绑定AppBar

通过NavigationUI绑定AppBar之后,导航时可以自动更新AppBar的内容。例如标题会显示我们在目的地里配置的android:label属性内容。

1.ActionBar

对于使用了含有ActionBar主题的Activity,我们可以通过NavigationUI的setupActionBarWithNavController()方法绑定ActionBar:

// 第一个参数是Activity,第二个是NavController
NavigationUI.setupActionBarWithNavController(this, navController);

2.Toolbar(推荐)

对于没有使用含有ActionBar主题的Activity,我们可以通过NavigationUI的setupWithNavController()方法绑定Toolbar。

// 第一个参数是Toolbar,第二个是NavController
NavigationUI.setupWithNavController(toolbar, navController);

该Toolbar在Activity的布局文件中,格式为:

<LinearLayout>
    <androidx.appcompat.widget.Toolbar
        android:id="@+id/toolbar" />
    <androidx.fragment.app.FragmentContainerView
        android:id="@+id/nav_host_fragment"
        ... />
    ...
</LinearLayout>

基于Toolbar可定制化程度高、应用场景多等优点,谷歌推荐使用Toolbar取代/作为ActionBar

补充

  • 如果Fragment需要使用Activity的AppBar,那么应该在Activity调用setSupportActionBar(toolbar)方法。
    即使这样会导致第一个目的地标题显示的是app name而不是自己的label。
  • 关于Fragment使用AppBar的细节,参考官方文档

三、AppBarConfiguration解释

通过AppBarConfiguration可以设置AppBar的一些特殊属性,例如:

// Builder构造方法里为top-level destinations。top-level destinations的AppBar没有返回箭头。
AppBarConfiguration appBarConfiguration = new AppBarConfiguration.Builder(R.id.cFragment)
        .setFallbackOnNavigateUpListener(new AppBarConfiguration.OnNavigateUpListener() {
// 给AppBar的返回键设置备用监听事件。NavController.navigateUp()返回false时触发,例如处于start destination时NavController.navigateUp()返回false
            public boolean onNavigateUp() {
            // 自定义AppBar的返回箭头事件
            // 例如可以为 requireActivity().onBackPressed();
                return true;
            }
        }).build();

NavigationUI.setupWithNavController(toolbar, navController, appBarConfiguration);

补充:如果没手动设置AppBarConfiguration,那么start destination默认是top-level destination。

四、Menu导航

如果MenuItem的id与目的地id一致,那么点击MenuItem时就可以使用NavigationUI.onNavDestinationSelected()方法实现导航。

假设导航图为
nav_graph.xml:

<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/nav_graph"
    app:startDestination="@id/aFragment">

    <fragment
        android:id="@+id/aFragment"
        android:name="com.scx.navigation.navigationui.AFragment"
        android:label="aFragment"/>
    <fragment
        android:id="@+id/bFragment"
        android:name="com.scx.navigation.navigationui.BFragment"
        android:label="bFragment{argName}" >
        <argument
            android:name="argName"
            app:argType="string"
            android:defaultValue="(arg)" />
    </fragment>

    <fragment
        android:id="@+id/cFragment"
        android:name="com.scx.navigation.navigationui.CFragment"
        android:label="CFragment" />

    <fragment
        android:id="@+id/dFragment"
        android:name="com.scx.navigation.navigationui.DFragment"
        android:label="DFragment" />
</navigation>

那么menu就应该为
menu.xml:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <!--   WARN: Item Id Must AS Same As Destination ID in nav_graph.xml-->
    <item
        android:id="@+id/aFragment"
        android:title="A" />
    <item
        android:id="@+id/bFragment"
        android:title="B" />
    <item
        android:id="@+id/cFragment"
        android:title="C" />
    <item
        android:id="@+id/dFragment"
        android:title="D" />
</menu>

只需在MenuItem的点击事件里调用NavigationUI.onNavDestinationSelected()方法即可实现导航:

toolbar.setOnMenuItemClickListener(item -> {
    NavigationUI.onNavDestinationSelected(item, navController);
    return true;
});

五、BottomNavigationView导航

通过NavigationUI.setupWithNavController()方法绑定BottomNavigationView实现BottomNavigationView导航。

  1. 在Activity的布局文件中添加BottomNavigationView
......
<!-- BottomNavigationView的menu为menu.xml -->
<com.google.android.material.bottomnavigation.BottomNavigationView
    android:id="@+id/bottom_nav"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="?android:attr/windowBackground"
    app:layout_constraintBottom_toBottomOf="parent"
    app:menu="@menu/menu" />
......
  1. 绑定BottomNavigationView
BottomNavigationView bottomNavigationView = findViewById(R.id.bottom_nav);
NavigationUI.setupWithNavController(bottomNavigationView, navController);

说明:

  • BottomNavigationView本质上就是Menu导航
  • 在导航时默认保存和恢复目的地的状态
  • 一般将BottomNavigationView对应的目的地设为top-level destinations

六、Navigation Drawer导航

本质上还是Menu导航,只不过在UI表现和使用方法上有所不同。

  1. 使用DrawerLayout + NavigationView
<?xml version="1.0" encoding="utf-8"?><!-- Use DrawerLayout as root container for activity -->
<androidx.drawerlayout.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <androidx.appcompat.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@color/design_default_color_primary"
            android:elevation="4dp"
            android:theme="@style/ThemeOverlay.Toolbar"
            app:contentInsetStartWithNavigation="0dp"
            app:layout_constraintTop_toTopOf="parent"
            app:titleTextColor="@color/white" />

        <!-- Layout to contain contents of main body of screen (drawer will slide over this) -->
        <androidx.fragment.app.FragmentContainerView
            android:id="@+id/nav_host_fragment"
            android:name="androidx.navigation.fragment.NavHostFragment"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:defaultNavHost="true"
            app:navGraph="@navigation/nav_graph" />
    </LinearLayout>


    <!-- Container for contents of drawer - use NavigationView to make configuration easier -->
    <com.google.android.material.navigation.NavigationView
        android:id="@+id/nav_view"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:fitsSystemWindows="true"
        app:headerLayout="@layout/header"
        app:menu="@menu/menu" />

</androidx.drawerlayout.widget.DrawerLayout>

  1. 绑定DrawerLayout和NavigationView
// 绑定DrawerLayout
DrawerLayout drawerLayout = findViewById(R.id.drawer_layout);
AppBarConfiguration appBarConfiguration = new AppBarConfiguration.Builder(R.id.aFragment)
        .setOpenableLayout(drawerLayout)
        .build();
NavigationUI.setupWithNavController(toolbar, navController, appBarConfiguration);

// 绑定NavigationView
NavigationView navigationView = findViewById(R.id.nav_view);
NavigationUI.setupWithNavController(navigationView, navController);

说明:top-level destinations的AppBar显示drawer icon

七、OnDestinationChangedListener

通过OnDestinationChangedListener监听导航事件。

使用方法:

navController.addOnDestinationChangedListener(new NavController.OnDestinationChangedListener() {
   @Override
   public void onDestinationChanged(@NonNull NavController controller,
          @NonNull NavDestination destination, @Nullable Bundle arguments) {
       //destination为当前destination,arguments为传递的参数 
   }
});

八、效果与代码

1.效果

Menu、BottomNavigationView导航:

Navigation Drawer导航:

2.代码

代码地址

ps:在AndroidManifest.xml中切换主Activity查看Drawer和其他类型的效果。

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值