简介 Google 2018 I/O大会上,Google正式推出了Android/Jetpack,其中隆重推出了一个新的架构组件:Navigation
Google 官方介绍:
作为构建您的应用内界面的框架,重点是让单 Activity 应用
成为首选架构。利用 Navigation 组件对 Fragment 的原生支持,您可以获得架构组件的所有好处(例如生命周期和 ViewModel),同时让此组件为您处理 FragmentTransaction 的复杂性。此外,Navigation组件还可以让您声明我们为您处理的转场。它可以自动构建正确的“向上”和“返回”行为,包含对深层链接的完整支持,并提供了帮助程序,用于将导航关联到合适的 UI 小部件,例如抽屉式导航栏和底部导航。
集成环境
Android Studio 3.2+ 下载地址:https://developer.android.com/studio/preview
添加依赖 Step-1: repositories 添加 Google 仓库和 classpath
1 2 3 4 5 6 7 8 buildscript { repositories { google() } dependencies { classpath "android.arch.navigation:navigation-safe-args-gradle-plugin:1.0.0-alpha01" } }
Step-2: 添加 Navigation 库的依赖
1 2 3 4 5 6 7 8 9 dependencies { def nav_version = "1.0.0-alpha01" implementation "android.arch.navigation:navigation-fragment:$nav_version" implementation "android.arch.navigation:navigation-ui:$nav_version" androidTestImplementation "android.arch.navigation:navigation-testing:$nav_version" }
新建 Navigation
新建 Android 项目
在 res
目录右键 New->New Resource File,弹出 New Resource File
的对话框
填写 File Name 如:nav_graph,Resource type 选择 Navigation
,点击OKAndroid Studio 3.3新建项目会自动生成该目录
以上操作会在 res
下生成一个 navigation
目录,目录下有刚才新建的 nav_graph.xml
文件,打开该文件,内容是一个 navigation
的空节点。和布局文件类似,AndroidStudio 界面上有
1 2 3 4 <?xml version="1.0" encoding="utf-8"?> <navigation xmlns:android ="http://schemas.android.com/apk/res/android" > </navigation >
使用 Navigation Step-1: 新建两个 Fragment:FragmentA、FragmentB 对应布局为 fragment_a.xml、fragment_b.xml
Step-2: 打开 nav_graph.xml
,底部选择 Design 选项卡,点击 New Destination
(左上角 + ) 按钮,在弹窗中选择 fragment_a.xml
、fragment_b.xml
,或选择 Create blank destination
新建Fragment.之后选显示如下界面:
此时 nav_graph.xml
内容如下,点击 Text
切换
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <?xml version="1.0" encoding="utf-8"?> <navigation xmlns:app ="http://schemas.android.com/apk/res-auto" xmlns:android ="http://schemas.android.com/apk/res/android" xmlns:tools ="http://schemas.android.com/tools" xmlns:tools ="http://schemas.android.com/tools" app:startDestination ="@id/fragmentA" > <fragment android:id ="@+id/fragmentA" android:name ="com.halove.jetpackdmeo.FragmentA" android:label ="fragment_a" tools:layout ="@layout/fragment_a" > </fragment > <fragment android:id ="@+id/fragmentB" android:name ="com.halove.jetpackdmeo.FragmentB" android:label ="fragment_b" tools:layout ="@layout/fragment_b" /> </navigation >
Step-3: 在 Activity 布局里添加 NavHostFragment
(关于 NavHostFragment 可以看这篇博客,解释的很清楚 https://blog.csdn.net/mq2553299/article/details/80445952 )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout 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:layout_width ="match_parent" android:layout_height ="match_parent" tools:context =".MainActivity" > <fragment android:id ="@+id/my_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" /> </android.support.constraint.ConstraintLayout >
app:defaultNavHost="true"
是拦截返回键,即将返回托管给NavHostFragment处理。否则返回直接退出当前 Activity 。app:navGraph="@navigation/nav_graph"
将 NavHostFragment 跟我们刚才创建的 navigation 关联。 然后重新打开 nav_graph.xml 会发现在 HOST 下面就会显示我们关联的 activity:
Step-4: 添加导航连接
左键按住 fragment 右侧中间的圆圈然后拖动到要导航的 fragment 然后松手
切换到 Text 模式下,发现在 fragment 标签里添加了一个 action 节点,action 添加了一个 id 和 destination ,destination 就是我们要导航到的 fragment。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 <?xml version="1.0" encoding="utf-8"?> <navigation xmlns:app ="http://schemas.android.com/apk/res-auto" xmlns:android ="http://schemas.android.com/apk/res/android" xmlns:tools ="http://schemas.android.com/tools" xmlns:tools ="http://schemas.android.com/tools" app:startDestination ="@id/fragmentA" > <fragment android:id ="@+id/fragmentA" android:name ="com.halove.jetpackdmeo.FragmentA" android:label ="fragment_a" tools:layout ="@layout/fragment_a" > <action android:id ="@+id/action_fragmentA_to_fragmentB" app:destination ="@id/fragmentB" /> </fragment > <fragment android:id ="@+id/fragmentB" android:name ="com.halove.jetpackdmeo.FragmentB" android:label ="fragment_b" tools:layout ="@layout/fragment_b" /> </navigation >
Activity 中不需要做任何操作,只需要设置布局即可:
1 2 3 4 5 6 7 class MainActivity : AppCompatActivity() { override fun onCreate (savedInstanceState: Bundle?) { super .onCreate(savedInstanceState) setContentView(R.layout.main_activity) } }
在 FragmentA 中布局中添加一个 Button ,点击跳转到 FragmentB :
1 2 3 4 5 6 7 8 override fun onActivityCreated (savedInstanceState: Bundle?) { super .onActivityCreated(savedInstanceState) to_fragmentb_btn.setOnClickListener { Navigation.findNavController(it).navigate(R.id.action_fragmentA_to_fragmentB) } to_fragmentb_btn.setOnClickListener(Navigation.createNavigateOnClickListener(R.id.action_fragmentA_to_fragmentB)) }
使用很简单,调用 Navigation 的 findNavController 方法找到 NavController , findNavController 还有其他参数的方法大家可以自己试试,然后调用 navigate 方法,参数就是 nav_graph.xml 里 action
的 id
。或者直接使用 createNavigateOnClickListener.
按返回键会回退到上一个 Fragment ,也可以调用 NavController 的 popBackStack 进行回退
页面传参 1 .代码传参
navigate 有好几个方法,如图所示:
可以使用Bundle传参
1 2 3 val bundle = Bundle() bundle.putString("param" , "I AM FROM FRAGMENT-A" ) Navigation.findNavController(it).navigate(R.id.action_fragmentA_to_fragmentC,bundle)
2. xml 文件传参 在 navigation 的xml的 fragment 的 action 里添加 argument
标签,然后使用生成的对应的 Agrs 或者 Directions 来传递参数,需要在 build.gradle 中添加 apply plugin: 'androidx.navigation.safeargs'
1 2 3 4 5 6 7 <fragment android:id ="@+id/fragmentB" android:name ="com.halove.jetpackdmeo.FragmentB" android:label ="fragment_b" tools:layout ="@layout/fragment_b" > <argument android:name ="text" android:defaultValue ="Hello" app:type ="string" /> </fragment >
传参:
FragmentBArgs 和 FragmentADirections 都是自动生成的,FragmentBArgs 是根据fragment 节点下的 argument 节点生成的,FragmentADirections 是根据 action 生成的
1 2 3 4 5 6 7 val bundle = FragmentBArgs.Builder().setText("Hello World" ).build().toBundle() Navigation.findNavController(it).navigate(R.id.action_fragmentA_to_fragmentB, bundle) val direction = FragmentADirections.action_fragmentA_to_fragmentB().setText("Hello World" ) Navigation.findNavController(it).navigate(direction)
3. 参数接收 1 2 3 val text = FragmentBArgs.fromBundle("key" ).text val text = arguments!!["key" ].toString()
转场动画
转场动画可以直接在 action 里面使用动画文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 <?xml version="1.0" encoding="utf-8"?> <navigation xmlns:app ="http://schemas.android.com/apk/res-auto" xmlns:android ="http://schemas.android.com/apk/res/android" xmlns:tools ="http://schemas.android.com/tools" app:startDestination ="@id/fragmentA" > <fragment android:id ="@+id/fragmentA" android:name ="com.halove.jetpackdmeo.FragmentA" android:label ="fragment_a" tools:layout ="@layout/fragment_a" > <action android:id ="@+id/action_fragmentA_to_fragmentB" app:destination ="@id/fragmentB" app:enterAnim ="@anim/slide_in_right" app:exitAnim ="@anim/slide_out_left" app:popEnterAnim ="@anim/slide_in_left" app:popExitAnim ="@anim/slide_out_right" /> </fragment > <fragment android:id ="@+id/fragmentB" android:name ="com.halove.jetpackdmeo.FragmentB" android:label ="fragment_b" tools:layout ="@layout/fragment_b" > <argument android:name ="text" android:defaultValue ="Hello" app:type ="string" /> </fragment > </navigation >
Demo 附上使用小 Demo
地址:https://github.com/wanglejun/NavigationDemo.git