谷歌官方组件Navigation你会用了吗?

6,854 阅读6分钟

转载请注明出处 [www.jianshu.com/p/b8307429e…]

上一篇文章我们介绍了谷歌官方组件Navigation的使用谷歌官方组件Navigation你了解了吗?,接下来我们来探究一下如何使用。

Navigation Editor

我们了解了Navigation之后,就不得不提Navigation Editor。我们可以通过Android Studio的 Navigation Editor去编辑和浏览我们的Navigation graph(导航图)

请注意这里必须要求我们的的Android Studio版本在3.3或者以上版本

目前也有很多文章介绍Navigation以及Navigation Editor但是更多的是介绍Android Studio3.3之前版本的,本篇文章着重介绍的是Android Studio3.3及以上版本,有很多不同之处。如需应用以下内容请先升级Android Studio至3.3或者以上版本。

开始使用Navigation Editor

1.环境配置

在Module下面的build.gradle当中

dependencies {
    def nav_version = "1.0.0"
    implementation "android.arch.navigation:navigation-fragment:$nav_version" // use -ktx for Kotlin
    implementation "android.arch.navigation:navigation-ui:$nav_version" // use -ktx for Kotlin
}
创建导航图

导航是发生在应用的目标示图之间——用户可以导航到应用当中的任何的位置。将这些目标视图通过操作来连接起来。
导航图是包括所有的目标视图和操作的一个资源文件,这个导航图标代表了我们应用的所有的导航路径图。

创建导航图需要以下几个步骤:
  1. 在Android Studio的主界面,在res目录的文件夹下面,选择New > Android Resource File然后我们就可以看到 New Resource File对话框。如下图:
  2. 在File name这一栏当中输入名称,比如“nav_graph”。
  3. 在Resource type下拉列表然后选择Navigation,点击ok就可以了。

如果我们是第一次创建导航图,Android Studio会在res文件夹下面创建一个navigation 的资源文件目录,这个目录当中就包含了我们刚才创建的资源文件。如图:

打开Navigation Editor控制面板

点击打开刚才创建的Navigation的xml文件,然后选择Design。 我们可以看到Navigation Editor控制面板自左向右有三部分如图:

控制面板分成了三部分分别是:

  1. Destinations panel(目标面板):列出当前导航的主机以及当前图解编辑器当中的所有目的地。
  2. Graph Editor(图解编辑器): 这里包含了导航图的。
  3. Attributes(属性):显示导航图中当前所选项的属性。

点击Text我们可以看到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">
</navigation>

这里的</navigation>是导航图的根元素,当我们要在图标当中添加目标视图和连接动作的时候,我们可以使用<destination><action>元素作为子元素。

在activity当中添加NavHost

一个主导航必须由NavHost派生而来,导航组件默认通过NavHost来实现,NavHostFragment来处理目标fragment直接的切换。

在XML文件当中添加NavHostFragment

在我们应用程序的main activity当中添加NavHostFragment 这里的添加有两种方式 1.复制下面代码到xml的代码文件当中

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

2.在design下面控制面板选择 位置如图:

然后我们直接拖NavHostFragment 的视图到我们的activity文件当中

在导航视图当中添加目标视图

这里总共有三种不同的方式可以在我们的导航视图当中添加目标视图

添加已经存在的目标视图

如果我们想把已经存在的目标视图想要添加在导航图当中,我们只需要点击New Destination然后找到已经存在目标视图,选择即可。
如图:

创建新的目标视图
  1. 在导航编辑器当中,点击New Destination然后再选择Create new destination 如图:
  2. 然后弹出了New Android Component对话框,然后我们可以创建fragment。 如图:
    填写完信息之后,我们就可以看到界面上出现了我们刚才创建的目标视图 如图:
  3. 创建占位目标视图 我们可以通过占位视图来表示未实现的目标视图。 如图:
连接目标视图

目标视图我们已经创建完成了,接下来我们就开始连接各个目标视图了。当然,我们连接目标视图就是通过Navigation Editor来完成。

  1. 在Navigation Editor当中打开Design 选项卡,然后我们可以看到右边有个小圆点,这个就是我们想要的导航起点。 如图:
  2. 然后拖拽鼠标,然后连接到了我们想要链接的目标视图。之后我们就可以看到一个线的箭头如图:
    这个就表示我们把两个目标视图连接了。
  3. 点击这条连接的线,我们可以看到高亮了,而这条线代表的就是我们之前说的Action(行为)我们可以看到右侧有相关属性。 如图:
  4. 点击Text选项,我们可以看到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" android:id="@+id/nav_graph"
           app:startDestination="@id/oneFragment">

   <fragment android:id="@+id/oneFragment" android:name="demo.rlv.cehome.com.navigationcomponents.OneFragment"
             android:label="fragment_one" tools:layout="@layout/fragment_one">
       <action android:id="@+id/action_oneFragment_to_twoFragment" app:destination="@id/twoFragment"/>
   </fragment>
   <fragment android:id="@+id/twoFragment" android:name="demo.rlv.cehome.com.navigationcomponents.TwoFragment"
             android:label="fragment_two" tools:layout="@layout/fragment_two"/>
</navigation>
导航到目标视图

导航到目标视图,我们需要用到NavController,它是用于管理NavHost中的应用程序导航的对象。 每个NavHost都有自己的相应NavController。
NavController有以下几种获取方式:

对于Java来说:

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

对于Kotlin来说:

  • Fragment.findNavController()
  • View.findNavController()
  • Activity.findNavController(viewId: Int)

下面我们就看一下在我们要实现的效果:

下面我们看一下实现代码,在OneFragment当中

   override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)
        view?.findViewById<Button>(R.id.button_one)?.setOnClickListener {
            view?.let { Navigation.findNavController(it).navigate(R.id.twoFragment)
            }
        }
    }

只需要添加就可以实现跳转功能,是不是很方便?

Navigation.findNavController(it).navigate(R.id.twoFragment)

对于Button控件来说,还有另一种实现跳转的方法

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)
//        view?.findViewById<Button>(R.id.button_one)?.setOnClickListener {
//            view?.let { Navigation.findNavController(it).navigate(R.id.twoFragment)
//            }
//        }
        button_one.setOnClickListener(Navigation.createNavigateOnClickListener(R.id.twoFragment, null))
    }

两种跳转分别是传入nav_graph.xml当中的action id和resource id。 两种方法都可以实现跳转,但是我更建议用第一种,因为第一种可以配合着过渡的动画使用。

popUpTo and popUpToInclusive

我们常见的一种逻辑如下: 有三个目标视图分别是A、B、C,有A到B,B到C,然后C到A。

可以看到当我们倒C之后,后台堆栈当中包括A、B、C单个实例。当我们通过popUpTo A回到A的时候,意味着我们从堆栈当中把B和C删除了。当我们使用app:popUpToInclusive =“true”的时候,我们还会把A弹出堆栈并有效的清除它。如果我们没有使用app:popUpToInclusive =“true”那么也意味着我们的堆栈当中包含两个A的实例。 实现代码如下:

  <action
        android:id="@+id/action_c_to_a"
        app:destination="@id/a"
        app:popUpTo="@+id/a"
        app:popUpToInclusive="true"/>

最后

当我尝试写这篇文章,并认真看过了官方文档,自己也实践之后发现Navigation以及Navigation Editor真的非常实用!在代码当中,我们不用写很多的Activity。写一个Activity嵌套多个Fragment就可以完成,当然这也是谷歌一直推崇的一种方式。那么不同的Fragment之间的跳转,可能就是摆在我们面前的一大难题,经常会有这样会那样的问题,同时逻辑不是很清晰并且需要大量的代码用来实现。但是有了Navigation和Navigation Editor之后就有效的解决了这一问题!

项目地址

github.com/yang0range/…

欢迎关注公共号

关注公共号会有更多收获!