5.4 Navigation + Compose 集成(二) 添加导航拦截

891 阅读1分钟

上一节对 Navigation 配置进行了拓展,这节拓展 Navigation 导航,添加拦截功能,默认实现一个路由无法找到的拦截器,避免导航到未知路由时报错。在下一节状态管理中应用导航拦截。

这些功能都是在保证不破坏原框架的基础上进行的拓展。

NavControllerKtx

在 lib_compose navigation 包下添加 NavControllerKtx.kt 文件

拦截器接口

interface NavInterceptor{
    /**
     * 是否需要拦截
     * @return Boolean true 拦截
     */
    fun shouldIntercept(
        route: String,
        navOptions: NavOptions?,
        navController: NavController
    ): Boolean

    /**
     *拦截后的导航逻辑
     */
    fun navigate(navController: NavController,originalRoute:String)
}

拓展 NavController.navigate()

不足之处在于,拦截器没有优先级,只会执行先匹配到的拦截器。(暂时没有遇到需要的场景,需要时再添加)

fun NavController.navigate(route: String, interceptors:List<NavInterceptor>? = null ,builder: NavOptionsBuilder.() -> Unit){
    val navOptions = navOptions(builder)
    //是否有需要拦截的拦截器
    val interceptor = interceptors?.find { it.shouldIntercept(route,navOptions,this) }

    if (interceptor != null){
        // 调用拦截器导航
        interceptor.navigate(navController = this, originalRoute = route)
    }else{
        navigate(route,navOptions)
    }
}

PageNotFind 拦截器

object NotFoundInterceptor:NavInterceptor{
    override fun shouldIntercept(
        route: String,
        navOptions: NavOptions?,
        navController: NavController
    ): Boolean {
        // 如果是 404 页面不拦截
        if (route == PageNotFoundScreen.route) return false

        //Compose navigate 是使用 DeepLink 匹配模式,
        //route 转换成 NavDeepLinkRequest 去 navController.graph 中匹配
        val request = NavDeepLinkRequest.Builder.fromUri(NavDestination.createRoute(route).toUri()).build()
        val requestMatch = navController.graph.matchDeepLink(request)
        return requestMatch == null
    }

    override fun navigate(navController: NavController,originalRoute:String) {
        navController.navigate(PageNotFoundScreen.route)
    }
}
// 404 页面 需要在 NavHost 参数的 NavGraphBuilder 中配置
object PageNotFoundScreen: Screen("pageNotFound"){
    override val root: String
        get() = "route404"
}

Navigation Compose 集成到这里就结束了,后续开发中如果遇到其他需求我们再来拓展。