移动端设计
概述
设计并构建在各个平台上都具有原生体验的移动应用。本技能涵盖 React Native、Flutter 和 SwiftUI,并深入了解特定平台的人机界面指南(Apple HIG)和 Material Design、手势处理、响应式布局、离线优先模式以及应用商店提交要求。
阶段 1:平台分析
- 确定目标平台(iOS、Android 或两者)
- 选择框架(React Native、Flutter、SwiftUI 或跨平台方案)
- 查阅特定平台的设计指南
- 定义导航架构
- 梳理离线需求
停止 — 在开始设计前,说明平台和框架建议及其理由。
框架选择决策表
| 需求 | React Native | Flutter | SwiftUI | Kotlin/Compose |
|---|
| 仅 iOS | 可行 | 可行 | 最佳 | 不支持 |
| 仅 Android | 可行 | 可行 | 不支持 | 最佳 |
| 跨平台 | 良好 | 最佳 | 不支持 | 不支持 |
| 对原生性能要求高 | 尚可 | 良好 | 最佳 | 最佳 |
| 现有 React Web 团队 | 最佳 | 学习成本较高 | 学习成本较高 | 学习成本较高 |
| 复杂动画 | 良好 | 最佳 | 良好 | 良好 |
| 快速原型开发 | 良好 | 良好 | 最佳(iOS) | 尚可 |
| 大型现有代码库(JS) | 最佳 | 重写 | 重写 | 重写 |
阶段 2:设计实现
- 构建包含平台变体的组件库
- 实现导航(标签栏、导航栈、抽屉)
- 处理安全区域和屏幕缺口
- 添加手势识别器
- 为手机和平板实现响应式布局
停止 — 提交导航架构和组件清单以供审核。
遵循平台特定的人机界面指南
Apple 人机界面指南
| 领域 | 指南 |
|---|
| 导航 | UINavigationController(推入/弹出),底部标签栏(最多 5 个) |
| 排版 | SF Pro / SF Pro Rounded,支持动态字体(全部 11 种大小) |
| 安全区域 | 遵循 safeAreaInsets — 切勿延伸至屏幕缺口或主屏幕指示器下方 |
| 手势 | 通过向后滑动进行导航,长按显示上下文菜单 |
| 触觉反馈 | UIFeedbackGenerator(冲击、选择、通知) |
| 颜色 | 语义系统颜色(label、secondaryLabel、systemBackground) |
| 模态窗口 | 使用工作表(.sheet、.fullScreenCover),支持拖动关闭 |
| 列表 | 设置使用分组内嵌样式,内容信息流使用普通样式 |
| 图标 | SF Symbols 图标库(5000+ 个图标,可调整字重和大小) |
Material Design(Android)
| 领域 | 指南 |
|---|
| 导航 | 底部导航栏、导航抽屉、顶部应用栏 |
| 排版 | Roboto / 产品字体、Material 字体比例 |
| 边到边 | 内容绘制到系统栏下方,处理窗口内边距 |
| 手势 | 预测性返回手势(Android 14+)、滑动关闭 |
| 触觉反馈 | HapticFeedbackConstants(点击、长按、键盘) |
| 颜色 | Material You 根据壁纸生成动态颜色和色调调色板 |
| 组件 | FAB、提示条、底部工作表、标签 |
| 动效 | 共享元素过渡、容器变换 |
跨平台模式决策表
| 功能 | iOS 模式 | Android 模式 |
|---|
| 返回导航 | 从左侧边缘滑动 | 系统返回按钮 |
| 主要操作 | 导航栏右侧按钮 | FAB |
| 警告框 | UIAlertController | MaterialAlertDialog |
| 加载指示器 | UIActivityIndicator | CircularProgressIndicator |
| 分段控件 | UISegmentedControl | 标签页 / 标签 |
| 日期选择器 | 滚轮选择器 | 日历选择器 |
| 下拉刷新 | 原生支持 | SwipeRefreshLayout |
| 上下文菜单 | 长按 + 触觉反馈 | 长按 + 弹出菜单 |
安全区域处理
React Native
import { SafeAreaView, useSafeAreaInsets } from 'react-native-safe-area-context';
function Screen() {
const insets = useSafeAreaInsets();
return (
<View style={{ flex: 1, paddingTop: insets.top, paddingBottom: insets.bottom }}>
{/* Content */}
</View>
);
}
Flutter
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: // Content
),
);
}
SwiftUI
var body: some View {
VStack {
// Content automatically respects safe areas
}
.ignoresSafeArea(.keyboard) // Only ignore keyboard if needed
}
手势导航模式
| 手势 | 用途 | 最小触控目标 |
|---|
| 点按 | 主要操作 | 44x44pt |
| 长按 | 上下文菜单 / 次要操作 | 44x44pt |
| 水平滑动 | 导航、关闭、显示操作 | 整行 |
| 垂直滑动 | 滚动、下拉刷新、关闭底部面板 | 整个区域 |
| 双指缩放 | 缩放图片 / 地图 | 内容区域 |
| 平移 / 拖动 | 重新排序、移动元素 | 拖动手柄 |
触控目标规则
| 规则 | 值 |
|---|
| 最小尺寸(iOS) | 44x44pt |
| 最小尺寸(Android) | 48x48dp |
| 最小间距 | 目标之间间隔 8pt |
| 视觉尺寸与触控尺寸 | 视觉尺寸可以更小;使用内边距扩大触控区域 |
| 主要操作 | 屏幕底部 1/3 区域(拇指可触及区域) |
第 3 阶段:平台精细化
- 平台专属的动画和转场
- 集成触觉反馈
- 应用图标和启动屏幕
- 支持深色模式和动态字体
- 应用商店元数据和截图
停止 — 宣布完成前,请在实体设备上进行测试。
响应式布局决策表
| 设备形态 | 布局 | 导航 |
|---|
| 手机竖屏 | 单列 | 底部标签栏 |
| 手机横屏 | 单列或分栏 | 侧边标签栏 |
| 平板竖屏 | 两列 | 侧边栏 |
| 平板横屏 | 三列 | 常驻侧边栏 |
React Native 响应式布局
import { useWindowDimensions } from 'react-native';
function useResponsive() {
const { width } = useWindowDimensions();
return {
isPhone: width < 768,
isTablet: width >= 768 && width < 1024,
isDesktop: width >= 1024,
columns: width < 768 ? 1 : width < 1024 ? 2 : 3,
};
}
Flutter 响应式布局
class ResponsiveLayout extends StatelessWidget {
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (context, constraints) {
if (constraints.maxWidth < 600) return MobileLayout();
if (constraints.maxWidth < 1200) return TabletLayout();
return DesktopLayout();
},
);
}
}
离线优先架构
| 层 | 模式 | 实现方式 |
|---|
| 数据 | 本地优先 | 使用 SQLite/Realm 作为主存储,以服务端作为同步目标 |
| 更新 | 乐观更新 | 在本地应用更新,在后台同步 |
| 冲突 | 解决策略 | 最后写入优先或按字段合并 |
| 队列 | 持久化操作 | 存储待处理操作,联网后重试 |
| 缓存 | 过期后重新验证 | 提供缓存内容,在后台刷新 |
实现检查清单
应用商店指南摘要
| 要求 | Apple App Store | Google Play Store |
|---|
| 截图 | 必须提供 6.7" 和 5.5" 尺寸,12.9" iPad 截图 | 每台设备最少 2 张,最多 8 张 |
| 应用图标 | 1024x1024px,不带透明度,不带圆角 | 512x512px,建议使用自适应图标 |
| 隐私 | 必须提供隐私营养标签 | 必须填写数据安全部分 |
| 审核时间 | 通常为 24-48 小时 | 数小时至数天 |
| 常见拒绝原因 | 崩溃、占位内容 | 违反政策、崩溃 |
性能目标
| 指标 | 目标 |
|---|
| 冷启动 | < 2 秒 |
| 屏幕转场 | < 300ms |
| 触控响应 | < 100ms |
| 滚动帧率 | 60fps(无掉帧) |
| 内存使用量 | < 200MB 基准值 |
| 应用大小 | < 50MB 下载大小 |
反模式 / 常见错误
| 反模式 | 错误原因 | 替代做法 |
|---|
| 在移动端使用 Web 模式(悬停状态) | 触控设备不支持悬停 | 使用按压 / 点按状态 |
| 触控目标过小(< 44pt) | 体验糟糕,无法满足无障碍要求 | 触控区域至少为 44x44pt |
| 在 Android 上使用 iOS 风格按钮 | 显得格格不入,令用户困惑 | 使用平台原生组件 |
| 针对单一屏幕尺寸使用固定布局 | 在平板和折叠屏设备上显示异常 | 使用带断点的响应式布局 |
| 在主线程上执行阻塞式 I/O | UI 冻结,出现 ANR 对话框 | 使用异步 I/O 和后台线程 |
| 未处理键盘弹出 | 内容被键盘遮挡 | 键盘弹出时调整布局 |
| 假设网络始终连接 | 离线时应用崩溃或卡住 | 采用离线优先架构 |
| 使用像素值而非 dp/pt | 不同屏幕上的尺寸各不相同 | 使用与密度无关的单位 |
| 跳过触觉反馈 | 应用显得廉价且响应迟钝 | 为关键交互添加触觉反馈 |
文档查询(Context7)
使用 mcp__context7__resolve-library-id,然后使用 mcp__context7__query-docs 获取最新文档。返回的文档优先于记忆中的知识。
react-native — 用于组件 API、导航或特定平台的模块
flutter — 用于 Widget 目录、状态管理或平台通道
集成点
| 技能 | 集成 |
|---|
ui-ux-pro-max | 调色板、排版、UX 指南 |
ui-design-system | 为移动端调整的设计令牌 |
canvas-design | 移动端数据可视化和图表 |
ux-researcher-designer | 移动端可用性测试 |
senior-frontend | React Native 组件实现 |
deployment | 应用商店提交流程 |
performance-optimization | 移动端性能分析 |
技能类型
FLEXIBLE — 根据所选框架和目标平台调整模式。面向单一平台时,应遵循特定平台的指南;跨平台应用则可灵活融合各种惯例。