行動裝置設計 — 完整技能
概覽
涵蓋 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 (Human Interface Guidelines)
- 導航: push/pop (UINavigationController)、分頁欄、模態表單
- 排版: SF Pro (San Francisco) — 閱讀用 New York (serif)
- 格線: 4pt 格線、邊距:16pt (標準)、20pt (大型)
- 顏色: 系統色(藍、綠、紅、橙、紫、粉、青、靛、灰)
- 觸控目標: 最小 44×44pt
- 返回手勢: 從左邊緣滑動
- 安全區域: 瀏海、home indicator (使用
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 (form sheet)、Android (bottom sheet) |
| 全螢幕模態 | 多步驟流程 | 兩者 |
| 滑動操作 | 列表項目的動作(刪除、封存) | 兩者 |
2.2 分頁欄規則
- 最多 5 個分頁 (iOS)、最多 5 個 (Material)
- 活躍狀態:實心圖示 + 標籤顏色變化
- 徽章:紅色圓點加上通知計數
- 安全區域:在 iOS 的 home indicator 上方
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 (filled、tinted、gray) | Elevated、filled、tonal、outlined、text |
| 列表 | UITableView (grouped、inset) | RecyclerView (list、card) |
| 輸入框 | UITextField | TextField (filled、outlined) |
| 切換開關 | UISwitch | Switch |
| 滑桿 | UISlider | Slider |
| 選擇器 | 滾輪選擇器 / 下拉選單 | 下拉選單 |
| 分頁欄 | UITabBar | BottomNavigationView |
| 搜尋 | UISearchBar | SearchBar |
| 提示 | N/A (使用自訂) | 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 個畫面: 價值主張 → 功能 → 權限 → 行動呼籲
- 跳過選項: 永遠可用
- 進度指示: 圓點或進度條
- 權限請求: 在請求前解釋原因
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 prop、避免在 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;圖示 →Icon搭配本地 XML 檔案 - 使用修飾詞前請閱讀元件的
.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 - 網頁目標:相同的
className可在 React Native Web 上運作 — 一套程式碼,三個平台
11.4 何時使用哪種
| 需求 | 使用 |
|---|---|
| 原生外觀 (SwiftUI/Compose) | @expo/ui 搭配 Host |
| 跨平台 + 快速迭代 | NativeWind v5 |
| 自訂繪圖 / 動畫 | Reanimated + Skia |
| 標準 RN 元件 | 內建 View/Text/Pressable |
12. 驗證檢查清單
- 已在真實裝置上測試 (不僅是模擬器)
- 淺色與深色模式皆測試
- 動態文字大小 (最小與最大)
- VoiceOver/TalkBack 導航
- 所有觸控目標皆可存取
- 最小螢幕 (iPhone SE) 上無版面問題
- 最大螢幕 (平板) 上無版面問題
- 流暢的 60 FPS 動畫
- 已處理離線狀態
- 權限請求附帶說明
- 所有列表皆有空狀態
- 所有非同步操作皆有錯誤狀態
- 載入狀態 (骨架、旋轉器)
- 表單中的鍵盤迴避
相關技能
$design-web— 網頁介面設計$design-desktop— 桌面應用程式設計$design-figma— Figma 設計工作$mobile-development— Expo/React Native 開發$testing-comprehensive— 測試行動與桌面應用程式