Android Jetpack - 使用 Navigation 管理页面跳转

2,691 阅读4分钟

使用如下 添加依赖 首先,需要使用 Android Studio 3.2 以上版本才能使用 Navigation。

在 build.gradle 中添加依赖:

implementation "android.arch.navigation:navigation-fragment:$nav_version"
implementation "android.arch.navigation:navigation-ui:$nav_version"

创建 navigation xml 文件

创建成功后,就来到了文章开头的那个一个可视化的操作界面。点击左上角的添加小图标,会出现 Activity 和 Fragment,我们这里添加两个 Activity 和两个 Fragment:

配置 Action

Fragment 的右边有个小圆圈,点击并拖到另一个页面,这样我们就给这个 Fragment 添加了一个跳转行为,也就是 Action。 但是可以发现,Activity 的右边是没有这个小圆圈的,所以 Navigation 并不能处理从 Activity 发起的跳转。

左上角有个小房子的是显示的第一个页面,但由于 Activity 无法发起跳转,所以这里把 MainActivity 删除,把 MainFragment 作为主页面,并给它添加跳转到 SecondFragment 和 SecondActivity 的 Action:

自动生成的 xml 代码是这样的:

<?xml version="1.0" encoding="utf-8"?>

<fragment
    android:id="@+id/mainFragment"
    android:name="com.example.navigation.MainFragment"
    android:label="fragment_main"
    tools:layout="@layout/fragment_main">
    <action
        android:id="@+id/action_mainFragment_to_secondFragment"
        app:destination="@id/secondFragment"
        app:enterAnim="@anim/slide_in_right" />
    <action
        android:id="@+id/action_mainFragment_to_secondActivity"
        app:destination="@id/secondActivity" />
</fragment>
<fragment
    android:id="@+id/secondFragment"
    android:name="com.example.navigation.SecondFragment"
    android:label="fragment_second"
    tools:layout="@layout/fragment_second" />
<activity
    android:id="@+id/secondActivity"
    android:name="com.example.navigation.SecondActivity"
    android:label="activity_second"
    tools:layout="@layout/activity_second" />

布局中添加 Fragment

现在,我们第一个页面是 MainFragment,而 Fragment 需要 Activity 作为容器,修改 MainActivity 的布局:

让navigation与Activity关联起来   现在我们已经创建了navigation,但是使用它还需要一个根Activity,它毕竟还是需要依托Activity的.

1.创建了一个叫DemoActivity的Activity.这个没啥,下面来看这个Activity的布局xml怎么配(如下xml代码)

  我们就关注fragment的一些属性

1.android:name="androidx.navigation.fragment.NavHostFragment"  这个非常重要,这是你告知fragment需要使用navigation模式的关键属性,另外它是固定死的.你必需写.

2. app:defaultNavHost="true"  这是你实现物理按键(比如返回键),是按一下退出一个fragment 还是直接退出这个Activity的关键属性

3.app:navGraph="@navigation/demo_nav"  很重要,这就是我们前面创建的navigation的xml文件

<?xml version="1.0" encoding="utf-8"?>

<fragment
    android:id="@+id/fragment"
    android:name="androidx.navigation.fragment.NavHostFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:defaultNavHost="true"
    app:navGraph="@navigation/nav" />

其中有三个属性需要注意。使用 android:name 指定 Fragment 的类型为 NavHostFragment,使用 app:navGraph 指定 Navigation 文件。app:defaultNavHost="true" 的作用是,让 Navigation 处理返回事件,点返回按钮时并不是返回上一个 Activity,而是返回上一个「页面」,上一个「页面」有可能是 Activity,也可能是 Fragment。 至此,Navigation 的简单配置就算完成了,接下来看如何使用它。

配置跳转

在 Navigation 里,页面的跳转是交给 NavController 来处理的,获取 NavController 的方法有这么三种:

NavHostFragment.findNavController(Fragment)
Navigation.findNavController(Activity, @IdRes int viewId)
Navigation.findNavController(View)

拿到后,通过 navigate 方法,通过传入 Action 的 id,实现跳转,比如:

NavHostFragment
        .findNavController(this)
        .navigate(R.id.action_firstFragment_to_secondFragment)

在简单配置了两个跳转后,看一下目前的效果:

传参

页面的跳转少不了数据的传递,使用 Navigation,和我们原来的跳转一样,可以通过 Bundle 来传递参数:

val bundle = Bundle()
bundle.putString("name", "SouthernBox")
NavHostFragment
        .findNavController(this)
        .navigate(R.id.action_firstFragment_to_secondFragment, bundle)

如果跳转到 Activity,可以从 intent.extras 获取到 bundle,如果是 Fragment,则从 arguments 获取到。 此外,还可以在 Navigation 的 xml 文件中配置传参,但这种方式目前支持的数据类型比较少,连 boolean 都不支持,而且我还碰到了 bug,所以目前不建议用。

转场动画

如果需要自定义的页面转场动画,使用 Navigation 可以很方便的实现。

这里举个例子,比如我们需要一个从右向左切入的过场动画,先创建这个动画的 xml 文件:

<?xml version="1.0" encoding="utf-8"?>
<translate
    android:duration="600"
    android:fromXDelta="100%"
    android:toXDelta="0" />

然后我们回到 Navigation 的可视化编辑页面来,点击跳转的线,右边会出现过场动画的配置选项,将 xxxx 设为刚才创建的动画:

这么简单就搞定了,效果如下:

参数传递

    在接收参数的fragment 编写argument
  <fragment android:id="@+id/regsiterFragment" android:name="com.bsoft.login.fragment.RegsiterFragment"
             android:label="RegsiterFragment">
    <argument android:name="userName"
              android:defaultValue="name"
              app:argType="string"/>
    <argument android:name="age"
              android:defaultValue="21"
              app:argType="integer"/>
</fragment>

跳转

     Bundle bundle = new Bundle();
            bundle.putString("userName", "jjkdasjkfjk");
            bundle.putInt("age", 13);
            NavController nav = Navigation.findNavController(mActivity, R.id.fragment);
            nav.navigate(R.id.action_loginTabMainFragment_to_regsiterFragment,bundle);

接收

ToastUtil.showLong(getArguments().getString("userName")+"=="+getArguments().getInt("age"));