写点什么

Android&Navigation 全面介绍 & 全新的 Fragment 管理器,kotlin 编程通俗演义 pdf

作者:嘟嘟侠客
  • 2021 年 11 月 27 日
  • 本文字数:6148 字

    阅读完需:约 20 分钟

| --- | --- || navigation | 导航或者说回退栈 || graph | 导航图 || destination | 目的地, 即在要跳转的页面 || pop | 出栈, 会一直将destination出栈, 直到到达指定 id 所在页面, 可以理解为 Fragment 的singleTask模式 || navHost | 即所有页面的容器. 类似网页中的 host, 所有 path 路径都是在 host 之后跟随, host 固定不变. |

XML


点击 NavResourceFile 中的 Design 即可查看布局编辑器, 布局编辑器分为三栏.


左侧是已添加的导航, 中间是页面浏览, 中间栏的工具栏可以创建和快速添加标签以及整理页面, 右侧属性栏方便添加属性.


navigation这是个嵌套的图表, 可以点击打开新的图表页面.


Activity 布局中


<LinearLayout.../><androidx.appcompat.widget.Toolbar.../><fragmentandroid:layout_width="match_parent"android:layout_height="0dp"android:layout_weight="1"android:id="@+id/my_nav_host_fragment"android:name="androidx.navigation.fragment.NavHostFragment"app:navGraph="@navigation/mobile_navigation"app:defaultNavHost="true"/><com.google.android.material.bottomnavigation.BottomNavigationView.../></LinearLayout>


android:name="androidx.navigation.fragment.NavHostFragment"


固定写法


app:navGraph 指定 navigation 资源文件, 也可以不指定后面通过代码中动态设置


app:defaultNavHost 是否拦截返回键事件, false 表示不需要回退栈.


手写创建 NavHostFragment 时并不会自动代码补全, 可以使用 Editor Designer 创建.



创建资源文件


res 目录创建 AndroidResourceFile 选择 Navigation. 然后 new-> NavigationResourceFile


navigation 节点


app:startDestination="@+id/home_dest" 指定初始目标


navigation 可以嵌套 navigation 标签.在布局编辑器中会显示为:



嵌套 navigation 无法互相关联


<navigationxmlns: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_global


《Android 学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》

【docs.qq.com/doc/DSkNLaERkbnFoS0ZF】 完整内容开源分享


"app:startDestination="@id/mainFragment">


<fragmentandroid:id="@+id/mainFragment"android:name="com.example.frameexample.MainFragment"android:label="fragment_main"tools:layout="@layout/fragment_main"><actionandroid:id="@+id/action_mainFragment_to_personInfoFragment"app:destination="@id/settingFragment" /></fragment>


<navigationandroid:id="@+id/navigation"app:startDestination="@id/settingFragment"><fragmentandroid:id="@+id/settingFragment"android:name="com.example.frameexample.SettingFragment"android:label="fragment_setting"tools:layout="@layout/fragment_setting" /></navigation>


</navigation>


上面的mainFragment无法直接app:destination="@id/settingFragment"这会导致运行错误. 只能先导航到navigation.(即 NavHostFragment 所在的界面)


fragment 节点


android:id 不言而喻


android:name 目标要实例化的 fragment 完全限定类名


tools:layout 用于显示在布局编辑器


android:label 用于后面绑定 Toolbar 等自动更新标题


argument 节点


android:name="myArg"app:argType="integer"android:defaultValue="0"


  • 参数名称

  • 参数类型

  • 参数默认值


在跳转导航页面的时候会自动在argument中带上参数(要求指定参数默认值). 数组和Paraclable/Serializable不支持默认值设置, 通过下面要讲的SafeArg可以在编译器校验参数类型安全问题.



action 节点


动作 用于页面跳转时指定目标页面


android:id="@+id/next_action"动作 idapp:destination="@+id/flow_step_two_dest">目标页面 app:popUpTo="@id/home_dest"当前属于弹出栈 app:popUpToInclusive="true/false"弹出栈是否包含目标 app:launchSingleTop="true/false"是否开启 singleTop 模式


app:enterAnim=""app:exitAnim=""导航动画


app:popEnterAnim=""app:popExitAnim=""弹出栈动画


如果从导航页面到新的 Activity 页面, 动画不支持. 请使用默认的 Activity 设置动画去支持.


全局动作


NavController 只能使用当前页面在 XMl 中的节点的子节点action. 不能使用其他的 Fragment 下的动作.


但是可以通过直接给navigation标签创建子标签action, 这属于全局动作, 即每个 Fragment 都能使用的动作.


<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_main"app:startDestination="@id/homeFragment">


<actionandroid:id="@+id/action_categoryFragment_to_main2Activity"app:destination="@id/main2Activity" />


<fragmentandroid:id="@+id/categoryFragment"android:name="com.example.frame.fragment.CategoryFragment"android:label="fragment_category"tools:layout="@layout/fragment_category"/>


</navigation>


占位页



占位页面如果运行时没有指定 Class 并且导航到该占位页面时会抛出异常


总结


一般情况下我们其实只会在 XML 中定义Fragment节点.


这些action|argument节点我认为主要是给 SafeArgsGradle 插件使用. 用于给插件扫描自动生成类比较方便, 如果不使用插件我不建议使用者两个节点, 在文章末尾会详细提及如果使用该插件. 该插件主要是自动处理参数的传递和获取以及目的地跳转.

类关系

NavController 控制导航的跳转和弹出栈


NavOptions 控制跳转过程中的配置选项, 例如动画和 singleTop 模式


Navigation 工具类 创建点击事件或者获取控制器 (鸡肋), 自己实现扩展函数可能更加方便.


NavHostFragment 导航的容器, 可以设置和获取导航图(NavGraph)


NavGraph 用于描述导航中页面关系的对象 可以增删改查页面,设置起始页等


NavigationUI 用于将导航和一系列菜单控件自动绑定的工具类


Navigator 页面的根接口, 如果想创建一个新的类型页面就要自定义他


NavigatorProvider 一个内部保存着[名称:Navigator]键值对的 HashMap. 一般情况不需要使用.


NavDeepLinkBuilder 构建一个能打开导航页面的 Intent


NavInflater 用于将 XML 创建成 NavGraph 对象, NavController 可以通过更方便的函数创建不需要直接使用这个类.


void NavInflater(@NonNull Context context,@NonNull NavigatorProvider navigatorProvider) // 要求当前 NavHostFragment 的内部变量// 构造函数, 但一般情况使用 NavController.getNavInflater 获取对象


void NavGraph inflate(@NavigationRes int graphResId)


NavBackStackEntry 表示一个目的地所对应

NavController

NavController 用于跳转页面和参数传递等控制, 可以通过扩展函数得到实例.


通过三个扩展函数可以得到实例


  1. Fragment.findNavController()

  2. View.findNavController()

  3. Activity.findNavController(viewId: Int) // NavHostFragment 的 Id

navigate

跳转目的


public void navigate(@IdRes int resId,@Nullable Bundle args,@Nullable NavOptions navOptions,@Nullable Navigator.Extras navigatorExtras) // 可设置共享元素动画参数


public void navigate(Uri deepLink,NavOptions navOptions,Navigator.Extras navigatorExtras)


  • resId都是可选参数


通过实现抽象类NavDirections创建自定义的对象来描述跳转目标(action)和传参(bundle)


public void navigate (NavDirections directions,NavOptions navOptions,Navigator.Extras navigatorExtras)


  • directions都是可选参数


resId可以是 XML 中的action或者destination节点 id, 如果是 action 则会附带 action 的配置, 如果是 destination 则不会附带 destination 节点下的子节点 action(写了白写).


args 即需要在 fragment 之间传递的 Bundle 参数, 但是导航还支持另外一种插件形式的传递参数方式-安全参数 SafeArgs, 后面提到.


navOptions 即导航页面一些配置选项(例如动画)


返回上级


public boolean navigateUp ()public boolean navigateUp (DrawerLayout drawerLayout)public boolean navigateUp (AppConfiguration appConfiguration)


出栈


弹出栈, 即从 Nav 回退栈中清除 Fragment.


public boolean popBackStack (int destinationId, // 目标 idboolean inclusive) // 是否包含参数目标


public boolean popBackStack ()// 弹出当前 Fragment


目的地变化监听器


每次进行跳转等页面变化时都会回调该监听器


public void addOnDestinationChangedListener (NavController.OnDestinationChangedListener listener)public void removeOnDestinationChangedListener (NavController.OnDestinationChangedListener listener)


public interface OnDestinationChangedListener {/**


  • 导航完成以后回调函数(但是可能动画还在播放中)

  • @param 控制导航到目标的导航控制器 NavController

  • @param 目标页面

  • @param 导航到目标页面的参数*/void onDestinationChanged(@NonNull NavController controller,@NonNull NavDestination destination, @Nullable Bundle arguments);}


DeepLink


NavDeepLinkBuilder createDeepLink ()// 内部就是调用的 DeepLinkBuilder 的构造函数


boolean handleDeepLink(Intent intent)


NavDestination getCurrentDestination ()


NavigatorProvider getNavigatorProvider ()


NavInflater getNavInflater()


Bundle saveState ()void restoreState (Bundle navState)// 用于处理 NavController 的状态获取和恢复


关于 NavGraph 函数


void setGraph(NavGraph graph,Bundle startDestinationArgs);


void setGraph(int graphResId,Bundle startDestinationArgs);


NavGraph getGraph ()


  • startDestinationArgs可选参数, 用于传递给起始目的地的参数对象

NavDirections

一个抽象类用于自定义动作和参数, 如果你想复用某个跳转逻辑就可以自定义继承该类. 一般情况下我们并不会手动去继承该类因为过于麻烦, 这个类主要是用于 SafeArgs 插件自动生成的派生类.

Navigator.Extras

前面提到参数 navigatorExtras 目前是用于支持转场动画的共享元素.


通过扩展函数可以快速创建


fun FragmentNavigatorExtras(vararg sharedElements: Pair<View, String>)


fun ActivityNavigatorExtras(activityOptions: ActivityOptionsCompat? = null, flags: Int = 0)


可以从源码看到内部都是使用的 Navigator.Extras.Builder 构造器创建的.

NavOptions

属于导航时的附加选项设置


XML 示例


<fragmentandroid:id="@+id/home_dest"android:name="com.example.android.codelabs.navigation.HomeFragment"android:label="@string/home"tools:layout="@layout/home_fragment">


<actionandroid:id="@+id/next_action"app:destination="@+id/flow_step_one_dest"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>


创建 NavOptions 对象相当于代码动态实现了 XML 中的<action>标签的属性设置(但是无法指定目标).


目前功能只有设置动画和 singleTop(启动模式), popUp(弹出栈)


创建对象


提供一个 DSL 作用域


fun navOptions(optionsBuilder: NavOptionsBuilder.() -> Unit): NavOptions


示例


val options = navOptions {anim {enter = R.anim.slide_in_right // 进入页面动画 exit = R.anim.slide_out_leftpopEnter = R.anim.slide_in_left // 弹出栈动画 popExit = R.anim.slide_out_right}


launchSingleTop = truepopUpTo = R.id.categoryFragment}


findNavController().navigate(R.id.flow_step_one_dest, null, options)


弹出栈


public NavOptions.Builder setPopUpTo (int destinationId,boolean inclusive)


函数并不会决定目的地, 只是在导航到目的地之前先执行一个弹出栈指令.


场景: 例如我现在购买一个商品支付成功, 这个时候我要将前面的商品详情; 订单配置等页面全部关闭 然后进入<支付成功>页面


顺便说下在之前的做法是发送事件然后 finish

NavDestination

表示当前目标对象


NavController可以获取NavDestination


findNavController().currentDestination


函数


void addDeepLink(String uriPattern)boolean hasDeepLink(Uri deepLink)


Navigator getNavigator()NavGraph getParent()


NavAction getAction(int id)void putAction(int actionId, NavAction action)void putAction(int actionId, int destId)void removeAction(int actionId)


void setDefaultArguments(Bundle args)void addDefaultArguments(Bundle args)Bundle getDefaultArguments()


void setId(int id)int getId()


void setLabel(CharSequence label)CharSequence getLabel()

NavHostFragment

该对象为 Navigation 提供一个容器


一般使用情况是在布局中直接定义, 但是也可以通过代码构建实例, 然后通过代码创建视图(例如 ViewPager 等)


public static NavHostFragment create (int graphResId)

UI 绑定

Navigation 可以与一系列视图组件进行联动


BottomNavigationView


通过扩展函数可以绑定多个导航图, 且关联 BNV.


fun BottomNavigationView.setupWithNavController(navGraphIds: List<Int>,fragmentManager: FragmentManager,containerId: Int,intent: Intent): LiveData<NavController>


  • navGraphIds 集合中包含 navGrap 的 Id. 每个 BNV 的按钮对应一个 navGrap.


ActionBar


设置导航到新页面时自动更新标题文字


fun AppCompatActivity.setupActionBarWithNavController(navController: NavController,drawerLayout: DrawerLayout?)


fun AppCompatActivity.setupActionBarWithNavController(navController: NavController,configuration: AppBarConfiguration = AppBarConfiguration(navController.graph))


这里出现个参数 AppBarConfiguration, 用于配置 Toolbar/ActionBar/CollapsingToolbarLayout.


AppBarConfiguration


构造器模式使用 Builder 创建实例


AppBarConfiguration.Builder(NavGraph navGraph)AppBarConfiguration.Builder(Menu topLevelMenu)AppBarConfiguration.Builder(int... topLevelDestinationIds)AppBarConfiguration.Builder(Set<Integer> topLevelDestinationIds)// 构造函数效果等同


函数


AppBarConfiguration.Builder setDrawerLayout(DrawerLayout drawerLayout)// 绑定 Toolbar 同时绑定一个 DrawerLayout 联动


AppBarConfiguration.Builder setFallbackOnNavigateUpListener(AppBarConfiguration.OnNavigateUpListener fallbackOnNavigateUpListener)// 监听返回操作


AppBarConfiguration build()


AppBarConfiguration.OnNavigateUpListener 该回调接口会在每次点击向上导航时回调


public interface OnNavigateUpListener {/**


  • 回调处理向上导航

  • @return 返回 true 表示向上导航, false 不处理*/boolean onNavigateUp();}


Toolbar


Toolbar 也可以绑定 Nav 自动更新对应页面的标题


源码:


fun Toolbar.setupWithNavController(

Android 进阶资料

以下的资料是近年来,我和一些朋友面试收集整理了很多大厂的面试真题和资料,还有来自如阿里、小米、爱奇艺等一线大厂的大牛整理的架构进阶资料。希望可以帮助到大家。


Android 进阶核心笔记



百万年薪必刷面试题



最全 Android 进阶学习视频


本文已被CODING开源项目:《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》收录

用户头像

嘟嘟侠客

关注

还未添加个人签名 2021.03.19 加入

还未添加个人简介

评论

发布
暂无评论
Android&Navigation全面介绍&全新的Fragment管理器,kotlin编程通俗演义pdf