011 结合 FirstComposeApp 重构 SettingsScreen 实战
今天我想和你分享一个我最近在项目里做的重构实战,它来自我的学习项目 FirstComposeApp。我选择 SettingsScreen.kt 这个页面来动刀,因为它麻雀虽小五脏俱全,非常适合用来练习如何组织一个真实的业务页面。
这个页面里同时包含了:
- Scaffold 骨架
- 底部导航
- 用户信息卡片
- 设置选项列表
- 版本更新弹窗
这已经远远超出了单个控件的练习范畴,而是一个需要整体考虑的完整页面了。下面我就来聊聊我是怎么重构它的,以及在这个过程中我的一些思考。
1. 重构前,我已经做了什么
在动手之前,我其实已经对项目里的 SettingsScreen.kt 做了一轮初步的整理和升级:
- 移除了冗余的滚动容器:之前是外层
Column套verticalScroll,里面再套一个LazyColumn,这种双重滚动让我看着就难受。 - 改用单一的
LazyColumn:现在整个内容区都由一个LazyColumn来承载,职责清晰多了。 - 为列表项添加了
key:在items(...)里加上了key,这是写LazyColumn的好习惯,能帮助 Compose 更高效地识别和重组项。 - 丰富了设置项模型:给每个设置项的数据模型补上了图标,让界面更完整。
- 动态获取版本号:把“版本检测更新”里的硬编码版本号,改成了读取
BuildConfig.VERSION_NAME,这样更真实。 - 解耦导航依赖:页面不再硬绑定
NavController,灵活性提高了。 - 新增了可运行的宿主 Activity:我专门创建了
SettingsActivity.kt,这样就能直接运行这个页面来预览和调试了。
做完这些,页面基础是扎实了,但我觉得结构上还能更好。
2. 原来的结构问题出在哪?
回顾一下最初那个“外层滚动 + 内层列表”的结构,在 Compose 里这通常是个坑。为什么呢?
主要是滚动职责混乱了。外层一个滚动,内层列表自己也有滚动,不仅容易产生测量和手势上的冲突,而且当你想在页面头部加东西,或者未来要做分组、分页时,这种结构会变得非常难以扩展和维护。
我的经验是:一个页面,尽量只保留一个主滚动容器。让这个容器来统一管理所有的滚动逻辑,这样代码会清晰很多。
3. 我是怎么重构的?关键思路在这里
3.1 让 LazyColumn 成为唯一的“舞台”
这次重构的核心,就是把整个页面内容都装进一个 LazyColumn 里。现在的结构看起来更像一个真实的项目了:
- 顶部的用户卡片 (
UserHeaderCard()) 用item { }来放置。 - 中间所有的设置项,用
items(...)来生成。 - 至于那个更新弹窗,它独立于列表存在,只在需要时显示。
这么改的好处非常明显:页面层次一下子清晰了。以后无论是想加分组标题、分割线,还是处理空状态、加载状态,都会非常自然。更重要的是,你培养了对列表性能的正确使用习惯。
3.2 彻底解耦:页面不关心“怎么跳转”
我注意到,当前这个学习项目还是多 Activity 的结构。如果 SettingsScreen 强依赖某个特定的 NavController,那它就绑死在这个导航环境里了,复用性很差。
所以这次我把它改成了回调式的参数设计:
- onOpenMessages: () -> Unit
- onOpenTalkieIdSetting: () -> Unit
- onOpenPlatformChannel: () -> Unit
页面只负责声明:“嘿,我这里有这么几个事件可能会发生”,至于点击后是跳转到另一个 Activity,还是用 Navigation 在同一个 Activity 内切换,页面本身完全不关心。
这其实是 Compose 推崇的一种设计模式:界面是纯粹的,它只负责发出事件信号,而导航逻辑则由调用方(如 ViewModel 或 Activity)来决定。
4. 为什么特意加了一个 SettingsActivity?
你可能觉得,写一个完美的 @Composable 函数不就够了吗?但对于学习来说,我觉得还不够。能“直接运行看到效果”带来的反馈感,是无可替代的。
新增 SettingsActivity.kt 就是为了这个:
- 它给 SettingsScreen 提供了一个真实的、可以承载它的宿主。
- 在我们这个多 Activity 的项目结构里,我能立刻运行起来,验证页面的样子和交互。
- 它还让我能从 MainActivity 的案例菜单里直接点进去,学习路径更顺畅。
这样一来,我的学习就形成了一个闭环:看概念 -> 写代码 -> 运行看效果 -> 再修改优化。而不是停留在“我好像读懂了代码”的层面。
5. 重构完了,还能怎么继续练?
这个页面现在是个很好的练习模板,你可以拿它来尝试更多东西:
练习 1:为设置项添加分组
现在所有设置项都混在一起。你可以试着把它们分类,比如“设备设置”、“平台配置”、“关于应用”。然后用 item { Text(...) } 插入分组标题,后面紧跟对应分组的 items(...)。这能练习如何组织更复杂的列表结构。
练习 2:将状态管理提升到 ViewModel
目前设置项的状态(比如开关状态)还是用 remember 在组件内部维护的。你可以尝试把它们迁移到 ViewModel 里,定义清晰的 UiState,甚至模拟一个 Repository 来提供数据。像版本号、用户账号这些信息,就是从“假数据”迈向“真实数据流”很好的练习点。
练习 3:丰富交互反馈
让点击操作更有响应性。比如:
- 点击“检查更新”后,按钮文字可以暂时变成“检查中...”。
- 点击进入“平台通道”设置时,可以把当前已选的配置作为参数传递过去。
- 点击用户头像区域,可以真的跳转到一个“个人资料”页面(哪怕先做个空的)。
练习 4:迁移到 Navigation Compose
等你把 MainActivity 里那套案例菜单玩熟了,可以挑战一下:把我们现在这个多 Activity 的示例项目,逐步迁移成单 Activity + NavHost 的架构。这是迈向现代 Android 开发的关键一步。
6. 通过这个页面,我们到底在学什么?
说到底,我们重构这个设置页,目标不是仅仅做出一个“能用的设置页”。而是要通过这个过程,掌握一套构建复杂 Compose 页面的核心能力:
- 组件拆分:如何将一个复杂的UI合理地拆分成一个个可复用的 Composable 组件。
- 状态组织:如何区分页面级状态和列表项内部的状态,并合理地管理它们。
- 容器协调:如何将列表、头部视图、弹窗等不同元素,优雅地组织在一个页面内。
- 关注点分离:如何让UI组件只关注渲染和事件抛出,而与具体的导航实现解耦。
7. 如果你想深入了解
这次重构涉及的知识点,在之前的笔记里都有铺垫,你可以联动阅读:
- 004-列表LazyColumn与RecyclerView对照.md
- 006-Navigation与多页面.md
- 007-与XML混合与渐进迁移.md
- 009-结合FirstComposeApp项目深入学习案例.md
如果你已经准备好向更完整的“项目级 Compose 架构”进发,我强烈建议你的下一步就是:把 MainActivity 里那个简单的案例菜单,升级成一个真正由 Navigation Compose 驱动的、带底部导航栏的 App 入口。那会是又一次质的飞跃。
当前文章价值4.7元,扫一扫支付后添加微信提供帮助!(如不能解决您的问题,可以申请退款)

评论已关闭!