モバイルデザイン — 完全スキル
概要
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 (ヒューマンインターフェースガイドライン)
- ナビゲーション: プッシュ/ポップ (UINavigationController)、タブバー、モーダルシート
- タイポグラフィ: SF Pro (San Francisco) — リーディング用 New York (セリフ)
- グリッド: 4pt グリッド、マージン: 16pt (標準)、20pt (大)
- カラー: システムカラー (青、緑、赤、オレンジ、紫、ピンク、ティール、インジゴ、グレー)
- タッチターゲット: 最小 44×44pt
- 戻るジェスチャー: 左端からのスワイプ
- セーフエリア: ノッチ、ホームインジケータ (
safe-area-insetを使用) - ダークモード:
UIColor { traitCollection }システム適応
1.2 Android (マテリアルデザイン 3)
- ナビゲーション: ボトムナビゲーション、ナビゲーションドロワー、トップアプリバー、戻るボタン
- タイポグラフィ: Roboto (システム)、Google Sans (ブランド)
- グリッド: 4dp グリッド、マージン: 16dp
- カラー: ダイナミックカラー (Material You)、トーンパレット
- タッチターゲット: 最小 48×48dp
- 戻るボタン: システムバック (Android 14 では予測型バック)
- エレベーション: 影は深度とインタラクションの優先度を表現
- リップル効果: すべてのインタラクティブ要素にタッチフィードバック
1.3 クロスプラットフォーム (React Native / Expo)
- 迅速なプロトタイピングには、まず Expo Go を使用
Dimensions.get()ではなくuseWindowDimensions()を使用- クロスプラットフォームの影には
boxShadowを使用 (レガシーな shadow/elevation は非推奨) - より優れた画像読み込みと SF Symbols のために
expo-imageを使用 - プラットフォーム固有のコード:
.ios.tsx/.android.tsx
2. モバイルナビゲーション
2.1 ナビゲーションパターン
| パターン | 使用タイミング | プラットフォーム |
|---|---|---|
| タブバー | 3〜5 のトップレベルデスティネーション | iOS (下部), Android (下部) |
| ボトムナビゲーション | 3〜5 のトップレベルデスティネーション | マテリアルデザイン |
| ナビゲーションドロワー | 多数のデスティネーション、アクセス頻度が低い場合 | 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 (filled、tinted、gray) | Elevated、filled、tonal、outlined、text |
| リスト | UITableView (grouped、inset) | RecyclerView (list、card) |
| 入力 | UITextField | TextField (filled、outlined) |
| トグル | UISwitch | Switch |
| スライダー | UISlider | Slider |
| ピッカー | Wheel picker / ドロップダウン | ドロップダウンメニュー |
| タブバー | 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 ダークモード
- システム全体の切り替え (OS 設定に従う)
- iOS ではピュアブラック (#000) (OLED)、Android ではダークグレー (#121212)
- ダークモードではコントラストを若干低くする
- すべての画面で両モードをテストする
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 画面: 価値提案 → 機能 → 権限 → CTA
- スキップオプション: 常に利用可能
- 進捗インジケーター: ドットまたはプログレスバー
- 権限リクエスト: リクエスト前に理由を説明
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 内の匿名関数を避ける)
- 画像のキャッシュと圧縮
- 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とコンポーネントのドキュメントを読んでください — Modifier は 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 - Modifier を使用する前にコンポーネントの
.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を使用します。1 回限りのスタイルにはstyleにフォールバック - Web ターゲット: 同じ
classNameが React Native Web で動作します — 1 つのコードベース、3 つのプラットフォーム
11.4 いつどれを使用するか
| ニーズ | 使用 |
|---|---|
| ネイティブルック (SwiftUI/Compose) | @expo/ui と Host |
| クロスプラットフォーム + 高速イテレーション | 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— モバイルおよびデスクトップアプリのテスト用