【NowInAndroid架构拆解】(8)UI层解析——ForYou页面展示

达到统一和和谐的第三种可能性是创造性的劳动,无论是艺术家还是手工业者的劳动都属于此类劳动。在每一种创造性的劳动中,创造者同他的物质------组成人的周围世界的物质达成一致。无论是木匠做一张桌子,还是金匠打一件首饰,无论是农民种田,还是画家作画------在每一种创造性的劳动中,劳动者和对象合二为一,人在创造的过程中同世界一致。但这一点只适用于自己计划、进行并看到成果的劳动。而在一个职员、一个流水作业线上的工人的现代化工作程序中几乎已经不存在劳动的这种特性。劳动者成为机器或官僚组织的一部分,他不再是"自我"------因为劳动者除了适应社会外,再没有与社会达成一致的可能性。

Composable的传递调用

在上一篇文章我们分析到,Activity.onCreate()中调用setContent{...},可创建Compose UI上下文。在这个上下文中调用@Composable函数,会生成相应的节点,并添加到节点树当中。

下面用伪代码分析MainActivity的节点树创建过程。

kotlin 复制代码
// MainActivity.kt
class MainActivity : ComponentActivity() { // ------> ComponentActivity提供了Lifecycle、ViewModel管理等功能
    ...
    setContnt {
        ...
        ComposisitonLocalProvider(...) {
            NiaTheme(...) {
                NiaApp(appState) // ------> 层层调用,对于作用域内所有被声明为@Composable的函数,都会建立相应节点
            }
        }
    }
}

// NiaApp.kt
@Composable
fun NiaApp(...) {
    NiaBackground(...) {
        NiaAGradientBackground(...) {
            LaunchedEffect() {...} // ------> 它也是Composable函数
            NiaApp(...) // ------> 指向内部另一个Composable函数
        }
    }
}

@Composable
internal fun NiaApp(...) {
    NiaNavigationSuiteScaffold(...) {
        Scaffold(...) {
            Column(...) {
                Box(...) {
                    NiaNavHost(...) {} ------> @Composable函数层层调用
                }
            }
        }
    }
}

// NiaNavHost.kt
@Composable
fun NiaNavHost(...) {
    NavHost(...) {
        forYourSection(...) { // ------> 连同下面的bookmarksScreen、searchScreen、interestsListDetailScreen,都是NavGraphBuilder的扩展函数,内部生成@Composable节点
            topicScreen(...)
        }
        bookmarksScreen(...)
        searchScreen(...)
        interestsListDetailScreen()
    }
}

在NiaApp中搭建脚手架

internal fun NiaApp() 这个函数,负责构建出包含底部Tab栏在内的整个界面,构建过程是从整体到局部,分层进行的:

  1. NiaNavigationSuiteScaffold: NIA自定义的脚手架,设置底部Tabs图标、颜色
  2. Scaffold: androidx.compose.material3 定义的页面级别脚手架,包含topBar、bottomBar、snackBar、floatingActionButton等支持自定义的属性
  3. Column、Box: 纵向布局+矩形容器

我感觉这种层层包装的设计,借鉴了装饰器模式,每一层装饰器都增加一部分额外属性,这样化繁为简、化整为零,同时提供重用的能力。

在NiaNavHost中注册路由

前文分析到,在MainActivity.onCreate函数中,setContent{...}创建了UI Compose上下文,在该上下文中,会调用到NavHost函数:

kotlin 复制代码
// NiaApp.kt
...
NiaNavHost(
    appState = appState,
    onShowSnackbar = { message, action ->
        snackbarHostState.showSnackbar(
            message = message,
            actionLabel = action,
            duration = Short,
        ) == ActionPerformed
    },
)

NiaNavHost 函数的主要功能是将NIA的路由注册到NavController当中,其中调用了NavGraphBuilder的几个扩展函数:

kotlin 复制代码
@Composable
fun NiaNavHost(
    appState: NiaAppState,
    onShowSnackbar: suspend (String, String?) -> Boolean,
    modifier: Modifier = Modifier,
) {
    val navController = appState.navController
    NavHost(
        navController = navController,
        startDestination = ForYouBaseRoute,
        modifier = modifier,
    ) {
        forYouSection( // ------> 扩展函数,创建ForYou路由,定义跳转关系,可跳转到Topic页面
            onTopicClick = navController::navigateToTopic,
        ) {
            topicScreen(
                showBackButton = true,
                onBackClick = navController::popBackStack,
                onTopicClick = navController::navigateToTopic,
            )
        }
        bookmarksScreen( // ------> 扩展函数,创建Bookmarks路由
            onTopicClick = navController::navigateToInterests,
            onShowSnackbar = onShowSnackbar,
        )
        searchScreen( // ------> 扩展函数,创建Search路由,支持跳转到Interests
            onBackClick = navController::popBackStack,
            onInterestsClick = { appState.navigateToTopLevelDestination(INTERESTS) },
            onTopicClick = navController::navigateToInterests,
        )
        interestsListDetailScreen() // 同样是NavGraphBuilder的扩展函数
    }
}

这里以文章收藏页 bookmarksScreen 为例,追溯它是如何加入到路由列表的。

首先,bookmarksScreen() 是作为扩展函数定义在 BookmarksNavigation.kt 文件当中的,在这个文件中同时也创建了路由跳转参数 BookmarksRoute ,用来对参数传递进行强约束。

kotlin 复制代码
@Serializable object BookmarksRoute // ------> 路由参数,可以包含属性

fun NavController.navigateToBookmarks(navOptions: NavOptions) =
    navigate(route = BookmarksRoute, navOptions)

fun NavGraphBuilder.bookmarksScreen( // ------> 作为NavGraphBuilder的扩展函数
    onTopicClick: (String) -> Unit,
    onShowSnackbar: suspend (String, String?) -> Boolean,
) {
    composable<BookmarksRoute> { // ------> 重点!将BookmarksRoute加入路由表
        BookmarksRoute(onTopicClick, onShowSnackbar)
    }
}
kotlin 复制代码
// NavGraphBuilder.kt
public inline fun <reified T : Any> NavGraphBuilder.composable(
    typeMap: Map<KType, @JvmSuppressWildcards NavType<*>> = emptyMap(),
    deepLinks: List<NavDeepLink> = emptyList(),
    ...
    noinline content: @Composable AnimatedContentScope.(NavBackStackEntry) -> Unit
) {
    destination( // ------> 将创建的ComposeNavigatorDestinationBuilder对象加入路由表
        ComposeNavigatorDestinationBuilder(
                provider[ComposeNavigator::class],
                T::class,
                typeMap,
                content
            )
            .apply {
                deepLinks.forEach { deepLink -> deepLink(deepLink) }
                this.enterTransition = enterTransition
                this.exitTransition = exitTransition
                this.popEnterTransition = popEnterTransition
                this.popExitTransition = popExitTransition
                this.sizeTransform = sizeTransform
            }
    )
}

// ------> 加入路由表
public fun <D : NavDestination> destination(navDestination: NavDestinationBuilder<D>) {
    destinations += navDestination.build()
}
相关推荐
canonical_entropy2 小时前
对《DDD本质论》一文的解读
后端·架构·领域驱动设计
haogexiaole3 小时前
Java高并发常见架构、处理方式、api调优
java·开发语言·架构
SmartBrain3 小时前
深入洞察:V模型架构实现业务到IT的服务化设计
华为·架构·创业创新
新知图书5 小时前
Encoder-Decoder架构的模型简介
人工智能·架构·ai agent·智能体·大模型应用开发·大模型应用
银帅183350309716 小时前
2018年下半年试题四:论NoSQL数据库技术及其应用
数据库·架构·nosql
文火冰糖的硅基工坊6 小时前
《投资-107》价值投资者的认知升级与交易规则重构 - 上市公司的估值,估的不是当前的净资产的价值,而是未来持续赚钱的能力,估的是公司未来所有赚到钱的价值。
重构·架构·投资·投机
文火冰糖的硅基工坊6 小时前
《投资-99》价值投资者的认知升级与交易规则重构 - 什么是周期性股票?有哪些周期性股票?不同周期性股票的周期多少?周期性股票的买入和卖出的特点?
大数据·人工智能·重构·架构·投资·投机
一水鉴天6 小时前
整体设计 逻辑系统程序 之18 Source 容器(Docker)承载 C/P/D 三式的完整设计与双闭环验证 之2
docker·架构·认知科学·公共逻辑
芒果茶叶7 小时前
并行SSR,SSR并行加载
前端·javascript·架构
数据智能老司机7 小时前
数据工程设计模式——冷热数据存储
大数据·设计模式·架构