在今年的 IO 大会上,发布了一套叫 Android Jetpack 的程序库。Android Jetpack 里的组件大部分咱们都接触过了,其中也有一些全新的组件,其中一个就是 Navigation。php
Navigation 是用来管理 APP 里页面跳转的。起初,我觉得它是用来代替 startActivity 的,但其实并非,你们往下看就知道它的做用了。java
另外,iOS 的同窗可能会有似曾相识的感受,Navigation 应该是有借鉴 Storyboard 的。android
咱们先来看看 Navigation 的实现过程。app
首先,须要使用 Android Studio 3.2 以上版本才能使用 Navigation。ide
在 build.gradle 中添加依赖:布局
implementation "android.arch.navigation:navigation-fragment:$nav_version"
implementation "android.arch.navigation:navigation-ui:$nav_version"
复制代码
使用 「Android Resource File」建立 xml 文件的时候,能够看到在类型里,多了一个 Navigation 的选项:gradle
建立成功后,就来到了文章开头的那个一个可视化的操做界面。点击左上角的添加小图标,会出现 Activity 和 Fragment,咱们这里添加两个 Activity 和两个 Fragment:动画
Fragment 的右边有个小圆圈,点击并拖到另外一个页面,这样咱们就给这个 Fragment 添加了一个跳转行为,也就是 Action。ui
可是能够发现,Activity 的右边是没有这个小圆圈的,因此 Navigation 并不能处理从 Activity 发起的跳转。this
左上角有个小房子的是显示的第一个页面,但因为 Activity 没法发起跳转,因此这里把 MainActivity 删除,把 MainFragment 做为主页面,并给它添加跳转到 SecondFragment 和 SecondActivity 的 Action:
自动生成的 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" xmlns:tools="http://schemas.android.com/tools" app:startDestination="@id/mainFragment">
<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" />
</navigation>
复制代码
如今,咱们第一个页面是 MainFragment,而 Fragment 须要 Activity 做为容器,修改 MainActivity 的布局:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent">
<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" />
</FrameLayout>
复制代码
其中有三个属性须要注意。使用 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"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate android:duration="600" android:fromXDelta="100%" android:toXDelta="0" />
</set>
复制代码
而后咱们回到 Navigation 的可视化编辑页面来,点击跳转的线,右边会出现过场动画的配置选项,将 xxxx 设为刚才建立的动画:
这么简单就搞定了,效果以下:
Navigation 的使用介绍就到这里。
你可能已经明白,Navigation 主要是用来处理 Fragment 的跳转,因此说它并非用来代替 startActivity,而是用来代替 FragmentTransaction 的相关操做。
在官方文档里,能够看到一个将传统跳转迁移到 Navigation 的建议。我简单理解为,将本来两个 Activity 之间的跳转,逐渐修改成使用一个 Activity 做为容器,用两个 Fragment 做为页面跳转。
看到这里,我联想到了在去年,Jake Wharton(目前在谷歌)有这么一个有争议的言论:
“一个 APP 只须要一个 Activity。”
在过去,要实现这种方式,就须要去解决复杂的 Fragment 堆栈处理,并且早期的 Fragment 坑比较多,处理很差容易出现页面穿透等问题。如今 Navigation 刚好解决了这些问题。
这一切联系起来,是否是能说明官方间接支持了「少用 Activity 多用 Fragment」的作法?你怎么看?