# Navigation
**Repository Path**: qiurongc/Navigation
## Basic Information
- **Project Name**: Navigation
- **Description**: No description available
- **Primary Language**: Kotlin
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2020-08-21
- **Last Updated**: 2021-09-03
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# Navigation [](https://jitpack.io/#runnchild/Navigation)
基于jetpack navigation改造的路由框架
## 一、功能介绍
1. 支持直接解析标准URL进行跳转
2. 支持多模块,组件化工程使用
3. 支持Activity/Fragment/Dialog路由跳转
4. 支持设置登录拦截
## 二、典型应用
1. 从外部URL映射到内部页面,以及参数传递
2. 跨模块页面跳转,模块间解耦
3. 拦截跳转过程,处理登陆逻辑
4. 跨模块API调用,通过控制反转来做组件解耦
## 三、基础功能
#### 1. 添加依赖和配置
Step 1. Add the JitPack repository to your build file
Add it in your root build.gradle at the end of repositories:
```
allprojects {
repositories {
...
maven { url 'https://jitpack.io' }
}
}
```
Step 2. Add the dependency
```
dependencies {
implementation 'com.github.runnchild.Navigation:navigation:2.0.0'
kapt 'com.github.runnchild.Navigation:compiler:2.0.0'
implementation "com.github.runnchild.Navigation:annotation:2.0.0"
}
```
Step 3. Add the kapt arguments
```
android {
kapt {
arguments {
arg("MODULE_NAME", project.module_name) //模块名称,例如:Home,Message,Mine
arg("PROJECT_NAME", project.name)
}
}
}
```
#### 2. 添加注解
```
@FragmentDestination("home/home", "首页-推荐", isStarter = true, isHomeTab = true, needLogin = false)
class HomeFragment : Fragment() {
}
```
#### 3. 发起路由
```
// 打开页面
navController().navigateBy(HomeNavigator.HOME_HOME)
// 携带参数
navController().navigateBy(HomeNavigator.HOME_HOME, bundleOf("key1" to "value1", "key2" to 100))
```
## 四、基本用法
使用前最好对[JitPack Navigation](https://developer.android.com/guide/navigation)有基本认识。
本库出发点是在使用Navigation实现单个Activity多Fragment的开发模式下,同样支持组件化或多模块间路由通讯。
也就是将定义在模块下res/navigation/navigation.xml的路由配置文件转换成字符串(url)以便与其他模块或跨平台通讯。
但也意味着有些初衷和功能与原库不一样,不过同样可以使用原库的所有方法。
以最简单的一个MainActivity多个Fragment构成的项目为例:
1. 创建MainActivity
```
class MainActivity : Activity() {
private lateinit var navController: NavController
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val navHostFragment =
supportFragmentManager.findFragmentById(R.id.nav_host) as NavHostFragment
navController = navHostFragment.navController
// 如果在注解中设置了isStarter=true
// NavGraphBuilder.build(this, navController, navHostFragment.id)
// 如果需要指定其他Fragment作为首个页面
NavGraphBuilder.build(this, navController, navHostFragment.id) { n, d ->
n.startDestination = AppAppNavigator.APP_MAIN_FRAGMENT.destId()
}
}
}
```
activity_main.xml
```
```
2. 创建Fragment页面:
```
@FragmentDestination("home/home", "首页", isStarter = true, needLogin = false)
class HomeFragment : Fragment() {
fun navigate(v: View) {
// 打开列表页面
v.findNavController().navigateBy(HomeNavigator.HOME_LIST)
}
}
@FragmentDestination("home/list", "列表页", needLogin = false)
class ListFragment : Fragment() {
// 打开详情页面
fun navigate(v: View) {
// Bundle 传参
v.findNavController().navigateBy(HomeNavigator.HOME_DETAIL, bundleOf("id" to 123, "type" to 1))
// Url 传参
v.findNavController().navigateByl("http://home/detail?id=123&type=1")
// or
v.findNavController().navigateBy(HomeNavigator.HOME_DETAIL.deepLink("123", 1))
// Uri
v.findNavController().navigateBy(uri)
}
}
@FragmentDestination("home/detail?id={id}&type={type}", title="详情页", doc="这是商品详情页", needLogin = true)
class ListFragment : Fragment() {
private val id by lazy { arguments?.getString("id") }
private val type by lazy { arguments?.getInt("type") }
fun backToList() {
navController().navigateUp()
}
fun backToHome() {
navController().popBackTo(HomeNavigator.HOME_HOME)
}
}
```
## 五、Api详细说明
> Destination注解:
```
@FragmentDestination(url="home/home", title="页面标题", doc="url的注释",isStarter=true, needLogin=true, animStyle = ANIMATE_POP)
url: 页面路由地址,由模块名称/页面名称组成,后面可以拼接参数,例如(/home/home?id=${id}&type=${type})
title: 页面标题,可作为ToolBar的标题。
doc: 页面注释
isStarter:是否是首页,整个项目应只有一个为true,或可以在后期指定其他的页面作为首页,参考前面基本用法。
needLogin: 打开此页面是否需要先登录。可设置路由拦截器实现相关业务。
animStyle: 页面打开动画,内置3种跳转动画:ANIMATE_POP 弹出式; ANIMATE_DEFAULT 从右到左; ANIMATE_NON 无动画; 如需要自定义动画可在跳转时配置,后面会详解。
@ActivityDestination/@DialogDestination同理。
```
配置好后 make一下就会在对应模块下生成HomeNavigator路由定义接口:
```
public interface HomeNavigator {
/**
* url的注释
*/
String HOME_HOME = "http://home/home";
}
```
> 页面跳转
```
// 页面跳转
navController.navigateBy(HomeNavigator.HOME_HOME)
// 页面带参跳转
navController.navigateBy(HomeNavigator.HOME_HOME, bundleOf("key" to "value"))
// 标准url跳转
navController.navigateBy("http://home/detail")
// 标准url带参跳转
navController.navigateBy("http://home/detail?id=123&type=1")
// deepLink跳转(前提是Fragment的注解的url地址为 "home/detail?id={id}&type={type}" )
navController.navigateBy(HomeNavigator.HOME_DETAIL.deepLink("123", 1))
// Uri跳转
val uri = intent.data
navController.navigateBy(uri)
```
> 更多操作
```
navController.navigateBy(HomeNavigator.HOME_HOME, options = navOptions {
// Whether this navigation action should launch as single-top
launchSingleTop = false
// 跳转前弹出到指定页面
popUpTo(HomeNavigator.HOME_LIST.destId()) {
// 是否包含此页面,如果为true,则会把HOME_LIST也一并弹出。
inclusive = true
}
// 跳转动画
anim {
// 详细参数注释参考 androidx.navigation.AnimBuilder
enter = R.anim.enter
exit = ...
popEnter = ...
popExit = ...
}
})
```
> 转场动画
```
navController.navigateBy(HomeNavigator.HOME_HOME, navExtra = FragmentNavigatorExtras { elements: Pair ->
transitionView1 to "transitionName1",
transitionView2 to "transitionName2",
transitionView3 to "transitionName3"
})
```
> 参数接收
```
@FragmentDestination("home/detail", title="详情页", doc="这是商品详情页", needLogin = true)
class ListFragment : Fragment() {
// 跳转时传递的参数都会设置在arguments里面,正常从里拿就是。
private val id by lazy { arguments?.getString("id") }
// 后期考虑自动解析...
private val type by lazy { arguments?.getInt("type") }
}
```
> 页面返回按下监听
```
requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner) {
navController().navigateUp()
}
```
> 页面返回时参数传递(onFragmentResult)
Fragment并不像Activity有onActivityResult方法,不过可以配合ViewModel实现,效果更完美:
```
class HomeFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// 在onViewCreated()设置结果监听
navController().observeCurrent("onFragmentResult") { result->
"result from NewFragment: $result".logd()
}
}
}
```
```
class NewFragment : Fragment() {
fun back() {
// 页面关闭前通知
navController.notifyPreBack("onFragmentResult", "This is NewFragment result")
navController.navgateUp()
// navController.previousBackStackEntry是上一个页面的相关信息,这在做埋点需求时很实用。
}
}
```
## 六、写在最后
目前商业项目应该很少人使用单个MainActivity搭配多个Fragment的方式写吧,刚看到JetPack的Navigation时还是很震撼的,遗憾的是无法在组件化的项目中使用。
本着爱瞎折腾精神改造了下
另可关注另外两个项目
[Feature](https://github.com/runnchild/Feature):超简洁,超实用MVVM开发框架。
[BuildConfig](https://github.com/runnchild/BuildConfig):项目build脚本配置插件