移动设计 — 完整技能
概述
涵盖 iOS 和 Android 设计:平台特有模式、导航、手势、排版、无障碍访问和现代趋势。融合了 building-native-ui、expo-ui-swiftui、expo-ui-jetpack-compose、engineering-mobile-app-builder、react-native-best-practices、expo-tailwind-setup 和 native-data-fetching。
1. 平台指南
1.1 iOS(人机界面指南)
- 导航: push/pop (UINavigationController)、标签栏、模态表单
- 排版: SF Pro (San Francisco) — New York (衬线体) 用于阅读
- 网格: 4pt 网格,边距:16pt(标准)、20pt(大)
- 颜色: 系统颜色(蓝色、绿色、红色、橙色、紫色、粉色、青色、靛蓝、灰色)
- 触控区域: 最小 44×44pt
- 返回手势: 从左侧边缘滑动
- 安全区域: 刘海屏、主页指示器(使用
safe-area-inset) - 深色模式:
UIColor { traitCollection }系统自适应
1.2 Android(Material Design 3)
- 导航: 底部导航、导航抽屉、顶部应用栏、返回按钮
- 排版: Roboto(系统)、Google Sans(品牌)
- 网格: 4dp 网格,边距:16dp
- 颜色: 动态颜色(Material You)、色调调色板
- 触控区域: 最小 48×48dp
- 返回按钮: 系统返回(Android 14 中的预测性返回)
- 高度: 阴影代表深度和交互优先级
- 涟漪效果: 所有交互元素上的触摸反馈
1.3 跨平台(React Native / Expo)
- 优先试用 Expo Go 用于快速原型设计
- 使用
useWindowDimensions()代替Dimensions.get() - 使用
boxShadow实现跨平台阴影(非传统的 shadow/elevation) - 使用
expo-image实现更好的图片加载和 SF Symbols - 平台特定代码:
.ios.tsx/.android.tsx
2. 移动端导航
2.1 导航模式
| 模式 | 使用场景 | 平台 |
|---|---|---|
| 标签栏 | 3-5 个顶级目的地 | iOS(底部)、Android(底部) |
| 底部导航 | 3-5 个顶级目的地 | Material Design |
| 导航抽屉 | 多个目的地,不频繁访问 | Android |
| 堆栈导航 | 分层下钻 | 两者 |
| 模态表单 | 聚焦任务、快速操作 | iOS(表单表单)、Android(底部表单) |
| 全屏模态 | 多步骤流程 | 两者 |
| 滑动操作 | 列表项操作(删除、归档) | 两者 |
2.2 标签栏规则
- 最多 5 个标签(iOS)、最多 5 个(Material)
- 激活状态:填充图标 + 标签颜色变化
- 徽章:带计数的红点用于通知
- 安全区域:在 iOS 的主页指示器上方
2.3 堆栈导航
- 推入:从右侧滑入(iOS)、淡入+滑入(Android)
- 弹出:从左侧边缘滑动(iOS)、返回按钮(Android)
- 过渡:300ms(iOS)、200-300ms(Android)
2.4 手势
- 滑动: 列表操作、屏幕间导航
- 下拉刷新: 列表的标准模式
- 长按: 上下文菜单(300-500ms 延迟)
- 捏合缩放: 图片、地图
- 双击: 缩放、点赞(社交应用)
3. 移动端排版
3.1 字号比例
| 样式 | 字号 | 字重 | 行高 |
|---|---|---|---|
| Large Title | 34pt | 700 | 41pt |
| Title 1 | 28pt | 700 | 34pt |
| Title 2 | 22pt | 700 | 28pt |
| Title 3 | 20pt | 600 | 25pt |
| Headline | 17pt | 600 | 22pt |
| Body | 17pt | 400 | 22pt |
| Callout | 16pt | 400 | 21pt |
| Subheadline | 15pt | 400 | 20pt |
| Footnote | 13pt | 400 | 18pt |
| Caption 1 | 12pt | 400 | 16pt |
| Caption 2 | 11pt | 400 | 13pt |
3.2 规则
- 最小字号: 12sp(Android)、11pt(iOS)
- 正文: 16-17pt 以获得舒适的阅读体验
- 行高: 字号的 1.3-1.5 倍
- 绝不截断: 关键文本(数字、姓名、日期)
- 行长: 最多 40-70 个字符
- 动态类型: 支持系统字体大小(iOS:
UIFontMetrics、Android:sp)
4. 移动端组件
4.1 通用组件
| 组件 | iOS | Android (Material) |
|---|---|---|
| 按钮 | UIButton (填充、着色、灰色) | Elevated、filled、tonal、outlined、text |
| 列表 | UITableView (分组、插入) | RecyclerView (列表、卡片) |
| 输入框 | UITextField | TextField (填充、轮廓) |
| 开关 | UISwitch | Switch |
| 滑块 | UISlider | Slider |
| 选择器 | 滚轮选择器/下拉菜单 | 下拉菜单 |
| 标签栏 | UITabBar | BottomNavigationView |
| 搜索 | UISearchBar | SearchBar |
| 提示 | 不适用 (使用自定义) | Snackbar |
4.2 列表模式
- 标准: 图标 + 标题 + 副标题 + 右箭头
- 操作: 向左滑动 → 删除/归档/分享
- 分组: 含分组项的分节标题
- 卡片: 图片 + 标题 + 描述 + 操作
- 无限滚动: 滚动时加载更多(带加载指示器)
4.3 表单模式
- 单列 始终(移动端)
- 标签: 输入框上方(不只是浮动)
- 键盘类型: 匹配输入(数字、邮箱、电话)
- 键盘回避: 键盘出现时滚动表单
- 验证: 字段下方内联显示,颜色变化
- 提交: 粘性底部按钮或表单操作
5. 移动端布局
5.1 安全区域
// Expo / React Native
import { useSafeAreaInsets } from 'react-native-safe-area-context';
const insets = useSafeAreaInsets();
<View style={{ paddingTop: insets.top, paddingBottom: insets.bottom }} />
5.2 屏幕密度
- iPhone SE: 375×667pt(最小)
- iPhone 14: 390×844pt
- iPhone 14 Pro Max: 430×932pt
- Android: 360×640dp(常见),差异较大
5.3 触控区域
- 最小: 44×44pt (iOS)、48×48dp (Android)
- 推荐: 48×48pt 用于拇指友好区域
- 间距: 相邻触控区域之间至少 8pt
5.4 拇指区域
- 最佳区域: 屏幕下半部分(拇指自然可达范围)
- 主要操作: 下方 1/3(尤其在大屏手机上)
- 破坏性操作: 远离主要操作区域
6. 移动端设计系统
6.1 颜色系统
/* 浅色模式 */
--primary: #007AFF; /* iOS 蓝色 / Android 蓝色 */
--background: #FFFFFF;
--surface: #F2F2F7;
--text-primary: #000000;
--text-secondary: #8E8E93;
--separator: #C6C6C8;
--success: #34C759;
--error: #FF3B30;
--warning: #FF9500;
/* 深色模式 */
--primary: #0A84FF;
--background: #000000;
--surface: #1C1C1E;
--text-primary: #FFFFFF;
--text-secondary: #8E8E93;
6.2 深色模式
- 系统级切换(遵循操作系统设置)
- 纯黑(#000)用于 OLED(iOS)或深灰色(#121212)用于 Android
- 深色模式下稍微降低对比度
- 为每个屏幕测试两种模式
6.3 图标
- iOS: SF Symbols(系统)、自定义图标(应用特定)
- Android: Material Icons(系统)、自定义图标
- 尺寸: 标准 24×24dp、小 18×18dp、大 28×28dp
- 样式: 填充(激活)、轮廓(未激活)
7. 动效与动画
7.1 原则
- 时长: 250-350ms(标准)、150-200ms(快速)、500ms 以上(复杂)
- 缓动:
cubic-bezier(0.2, 0, 0, 1)(Material)、ease-out(iOS) - 目的: 指示导航、确认操作、显示加载、增添愉悦感
7.2 常见模式
| 动画 | 时长 | 用途 |
|---|---|---|
| 页面推入/弹出 | 300ms | 堆栈导航 |
| 模态呈现/关闭 | 300ms | 模态表单 |
| 淡入 | 200ms | 内容加载 |
| 上滑 | 250ms | 底部表单 |
| 放大 | 200ms | 按钮按下反馈 |
| 骨架屏 | 1.5s 循环 | 内容加载 |
| 下拉刷新 | 200ms | 列表刷新 |
7.3 平台特定
- iOS: 弹簧物理(自然、有弹性)
- Android: 标准缓动(可预测、平滑)
- 触觉反馈: 轻触(按钮按下)、中等(选择)、成功/错误模式
8. 移动端 UX 模式
8.1 引导页
- 最多 3-5 屏: 价值主张 → 功能 → 权限 → 行动号召
- 跳过选项: 始终可用
- 进度指示器: 圆点或进度条
- 权限请求: 在请求之前解释 WHY
8.2 空状态
- 插画或图标
- 清晰的消息
- 行动号召按钮
- 示例:“无结果”、“您的购物车为空”、“无通知”
8.3 加载状态
- 骨架屏(优先于旋转器)
- 进度条 用于可度量的操作
- 下拉刷新 用于列表
- 乐观 UI 用于操作(立即更新,出错时回滚)
8.4 错误状态
- 内联: 字段级验证错误
- 全屏: 带有重试按钮的严重错误
- 提示/快照栏: 瞬时错误(3-5 秒)
- 离线: 缓存内容 + “您已离线”横幅
8.5 通知
- 推送: 附带解释的权限请求
- 应用内: 徽章、横幅或收件箱
- 设置: 精细控制(按类别)
9. 无障碍访问
9.1 检查清单
- 所有触控区域 ≥ 44×44pt
- 文本支持 Dynamic Type / 字体缩放
- 色彩对比度 ≥ 4.5:1
- 所有图片都有替代文本 (accessibilityLabel)
- 屏幕阅读器:VoiceOver (iOS) / TalkBack (Android)
- 焦点顺序遵循视觉顺序
- 重要操作有触觉反馈
- 尊重减少动效设置
- 无仅依赖颜色传达信息
- 表单有正确的标签
9.2 屏幕阅读器
- iOS VoiceOver:
accessibilityLabel、accessibilityHint、accessibilityTraits - Android TalkBack:
contentDescription、accessibilityRole - 测试: 启用屏幕阅读器并导航整个应用
10. 性能
10.1 关键指标
- TTI(可交互时间): < 2s
- 帧率: 60 FPS(每帧 16.67ms)
- 应用体积: 最小化包体
- 内存: 无泄漏,正确清理
10.2 优化
- 对长列表使用
FlatList(而非 ScrollView) - 记忆化昂贵组件(
React.memo、useMemo、useCallback) - 懒加载屏幕和图片
- 减少重新渲染(正确的 key props,避免在 props 中使用匿名函数)
- 图片缓存与压缩
- 为 React Native 使用 Hermes 引擎
11. Expo 原生 UI 组件
11.1 Expo UI — SwiftUI (iOS)
npx expo install @expo/ui
import { Host, SwiftUIButton } from '@expo/ui/swift-ui';
export default function Screen() {
return (
<Host> {/* 每个 SwiftUI 树都需要 Host */}
<SwiftUIButton title="Tap me" action={onPress} />
</Host>
);
}
- ⚠️ 每个 SwiftUI 树必须包裹在
Host中 — 否则不会渲染任何内容 - 使用
RNHostView将 React Native 组件嵌入 SwiftUI 树中 - 使用前请阅读包的
.d.ts和组件文档 — 修饰符在不同 SDK 版本之间可能发生变化
11.2 Expo UI — Jetpack Compose (Android)
import { Host, Button } from '@expo/ui/jetpack-compose';
import { composeModifiers } from '@expo/ui/jetpack-compose/modifiers';
<Host>
<Button title="Tap me" modifiers={[composeModifiers.padding(16)]} onPress={onPress} />
</Host>
- ⚠️ 每个 Compose 树必须包裹在
Host中(与 SwiftUI 相同规则) - 长列表 →
LazyColumn;图标 → 使用本地 XML 文件的Icon - 使用修饰符前请阅读组件的
.d.ts— API 是 SDK 版本特定的
11.3 NativeWind v5 + Tailwind v4(跨平台样式)
npm i nativewind react-native-css tailwindcss @tailwindcss/postcss
// src/tw/index.tsx — 支持 className 属性的包裹组件
import { styled } from 'nativewind';
export const View = styled(NativeView);
- 无需修改
babel.config.js— react-native-css 在运行时处理转换 - 输出位于
src/tw/(包裹的View、Text、Image、animated) - 随处使用
className;对于一次性样式回退到style - Web 目标:相同的
className在 React Native Web 上同样有效 — 一套代码,三个平台
11.4 何时使用哪种
| 需求 | 使用 |
|---|---|
| 原生外观 (SwiftUI/Compose) | 带 Host 的 @expo/ui |
| 跨平台 + 快速迭代 | NativeWind v5 |
| 自定义绘图/动画 | Reanimated + Skia |
| 标准 RN 组件 | 内置的 View/Text/Pressable |
12. 验证检查清单
- 在真机上测试(不仅是模拟器)
- 测试浅色和深色模式
- 动态文本大小(最小和最大)
- VoiceOver/TalkBack 导航
- 所有触控区域可达
- 最小屏幕(iPhone SE)无布局断裂
- 最大屏幕(平板)无布局断裂
- 流畅的 60 FPS 动画
- 处理离线状态
- 附带解释的权限请求
- 所有列表有空状态
- 所有异步操作有错误状态
- 加载状态(骨架屏、旋转器)
- 表单中的键盘回避
相关技能
$design-web— 用于 Web 界面设计$design-desktop— 用于桌面应用设计$design-figma— 用于 Figma 设计工作$mobile-development— 用于 Expo/React Native 开发$testing-comprehensive— 用于测试移动和桌面应用