支付页面 UI 设计总览
支付页面是电商与金融类应用的核心转化漏斗,其布局结构、组件层级与响应能力直接影响用户付款成功率。本章从典型商用支付页面入手,拆解通用布局模式,逐层剥离 UI 组件,最终映射为 Jetpack Compose 组件树,为后续章节的代码实现提供静态结构基线。
典型布局分析
经过对 30+ 款主流支付页面(支付宝、微信支付、Stripe、Shopify 结账页)的抽样分析,支付页面布局可归纳为三种核心模式:
| 模式 | 典型特征 | 适用场景 |
|---|---|---|
| 单列纵向流 | 从上至下依次展开:品牌条、金额、支付方式列表、确认按钮、安全提示 | 移动端全屏展示,用户注意力引导明确 |
| 双栏并排 | 左侧支付选项(列表/卡片),右侧订单摘要 + 确认按钮 | 平板或桌面宽屏,减少滚动深度 |
| 嵌套抽屉 | 初始显示精简摘要,点击后展开支付方式详情/二维码 | 第三方唤起支付时快速返回到原有界面 |
选型提示:单列纵向流在 Compose 中使用
LazyColumn + stickyHeader 实现最为自然;双栏布局需避免嵌套垂直滚动,推荐使用 Row + 固定高度容器。
UI 组件层级拆解
支付页面从顶层到底层可拆解为 7 个主要层级。每个层级承担明确的 UI 职责与交互逻辑:
- 壳层(Shell):页面容器,处理系统状态栏、安全区域、全局加载/错误遮罩。
- 顶部导航:后退按钮、页面标题(如“确认付款”)、额外操作图标。
- 金额展示区:支付金额主数字、货币符号、金额说明(含/不含手续费提示)。
- 支付方式选择:单选卡片列表、新增卡入口、余额/积分开关。
- 订单信息摘要:商品名称、数量、小计、优惠券明细(可选折叠)。
- 确认按钮:主操作按钮、付款文案、加载状态(支付处理中)。
- 安全与法律声明:小字号安全标识、隐私协议链接、服务条款。
关键设计原则:每个层级尽量保持独立 ViewModel 状态槽位,避免跨层级状态耦合。金额展示区与支付方式选择区之间存在实时联动(如选择信用卡后金额旁显示手续费),应通过向上传递回调或共享 ViewModel 控制。
Compose 组件树构建
将上述层级映射到 Compose 可组合函数,形成清晰的组件树。节点按职责分组,父节点仅做布局编排,子节点持有具体交互逻辑。
// 伪代码:从壳到叶的组件树关系
PaymentScreen(
onBackClick = { /* 返回处理 */ },
onPay = { /* 支付回调 */ },
modifier = Modifier.fillMaxSize()
) {
val viewModel: PaymentViewModel = viewModel()
// 壳层:Scaffold + Column
Scaffold(topBar = { PaymentTopBar() }) { innerPadding ->
Column(modifier = Modifier.padding(innerPadding)) {
// 金额展示区
AmountDisplay(
amount = viewModel.amount,
currency = "CNY",
modifier = Modifier.fillMaxWidth()
)
// 支付方式选择区(内含单选列表)
PaymentMethodSelector(
methods = viewModel.methods,
selectedMethod = viewModel.selectedMethod,
onMethodSelected = { viewModel.selectMethod(it) }
)
// 订单摘要(可折叠)
OrderSummary(order = viewModel.order)
// 确认按钮(含加载状态)
PayButton(
isLoading = viewModel.isProcessing,
enabled = viewModel.canPay,
onClick = { viewModel.startPayment() }
)
// 安全声明
SecurityNotice()
}
}
}
常见层级错误:将金额展示与支付方式选择直接耦合在同一个
Row 中,导致状态更新时整个 Row 重组。正确做法是使用 key 或 derivedStateOf 隔离重组范围,或拆分为独立的 @Composable 函数。
支付页面组件层级结构图
下图展示支付页面从壳层到叶节点的完整组件树,箭头表示父→子包含关系,虚线框表示可选/条件渲染组件:
调试与验证要点
在搭建组件树阶段,应通过 Compose 布局检查工具验证以下两点:
- 嵌套深度:避免超过 10 层嵌套,否则会影响重组性能。使用
Layout Inspector查看每个节点的重组次数。 - 父级滚动冲突:若
PaymentMethodSelector内部包含可滚动的LazyColumn,其父容器Column必须换成Box固定高度,或启用nestedScroll协调。
性能陷阱:在组件树中,
AmountDisplay 与 PayButton 若共用同一个 Column 并依赖 lambda 回传状态,容易导致不必要的重组。建议将这两个组件各自包裹在 remember 稳定的状态读取点中,或使用 derivedStateOf 隔离。
作业与自检
绘制你正在开发的支付页面的组件树,然后对照下表确认是否遗漏通用层级:
| 层级编号 | 必需性 | 常见遗漏 |
|---|---|---|
| 1 壳层(Screen容器) | 必须 | 缺少系统状态栏安全边距处理 |
| 2 顶部导航 | 必须 | 无返回按钮(影响手势返回) |
| 3 金额展示 | 必须 | 未显示货币符号或精度错误 |
| 4 支付方式选择 | 必须 | 缺少新增卡入口 |
| 5 订单摘要 | 推荐 | 优惠券信息不直观 |
| 6 确认按钮 | 必须 | 加载状态与正常状态未分离 |
| 7 安全声明 | 建议 | 经常被省略导致合规风险 |