― Previewは「確認ツール」ではなく「設計レビュー装置」 ―
※ChatGPTを使用して記事を作成しています。
Jetpack Compose を使っていると、ほぼ全員が Preview を使います。
- UIの見た目確認
- レイアウトの微調整
- ダークモードの確認
しかし多くの場合、Previewはここで止まります。
「とりあえず表示できればOK」
これは非常にもったいない使い方です。
実は Preview は、
UI設計の正しさをチェックできる強力なツール
です。
この記事では、
- Previewが設計に効く理由
- Previewで見抜ける設計ミス
- 実務で使えるPreview設計パターン
を解説します。
■ Previewはなぜ設計に効くのか
Composeの本質はこれでした。
UI = State の結果
そして前回の記事で扱った通り、
- UIは状態とイベントだけを受け取る
- ViewModelはUIから切り離す
この設計ができていると、どうなるか。
👉 PreviewでそのままUIが再現できる
逆に言うと、
PreviewできないUIは、設計が崩れている可能性が高い
■ 失敗例:PreviewできないComposable
@Composable
fun UserProfile(viewModel: UserViewModel = viewModel()) {
val user by viewModel.user.collectAsState()
Text(user.name)
}
このコードはPreviewできません。
なぜなら:
- ViewModelが必要
- Flowが必要
- ライフサイクルが必要
つまり、
UI単体で成立していない
■ PreviewできるUIの条件
PreviewできるUIは必ずこの形になります。
@Composable
fun UserProfile(
state: UserProfileUiState,
onClick: () -> Unit
)
つまり、
- 状態は引数
- イベントはコールバック
です。
この時点で、
- 再利用可能
- テスト可能
- Preview可能
という理想状態になります。
■ 基本のPreview
@Preview
@Composable
fun PreviewUserProfile() {
UserProfile(
state = UserProfileUiState(
name = "Taro",
isFollowing = false
),
onClick = {}
)
}
これは単なる確認ではありません。
👉 設計が正しいかの検証
です。
■ Previewで“状態設計”を検証する
良いPreviewは、1つでは足りません。
複数の状態を用意します。
正常状態
@Preview(name = "Normal")
@Composable
fun PreviewNormal() {
UserProfile(
state = UserProfileUiState("Taro", false),
onClick = {}
)
}
フォロー済み
@Preview(name = "Following")
@Composable
fun PreviewFollowing() {
UserProfile(
state = UserProfileUiState("Taro", true),
onClick = {}
)
}
ローディング
@Preview(name = "Loading")
@Composable
fun PreviewLoading() {
UserProfile(
state = UserProfileUiState.loading(),
onClick = {}
)
}
ここで分かることがあります。
状態が増えるほど、UI設計の甘さが露呈する
- 分岐漏れ
- 表示崩れ
- null依存
👉 Previewは「状態網羅チェック」に使える
■ Previewが教えてくれる設計の問題
① 引数が多すぎる
fun UserProfile(
name: String,
age: Int,
isFollowing: Boolean,
isLoading: Boolean,
errorMessage: String?
)
Previewを書くのが辛くなります。
👉 Stateにまとめるべきサイン
② 状態が曖昧
errorMessage: String?
isLoading: Boolean
Previewで「どの状態を作ればいいか分からない」
👉 正規化されていない
③ ViewModel依存
Previewが書けない
👉 責務分離が崩れている
■ Preview Driven Development
ここで一歩進めます。
Previewを先に書く
です。
手順
① Stateを定義
② Previewを書く
③ UIを実装する
例
data class UiState(
val title: String,
val isLoading: Boolean
)
@Preview
@Composable
fun PreviewSample() {
SampleScreen(
state = UiState("Hello", false)
)
}
👉 ここからUIを書く
この方法のメリット:
- UI仕様が明確になる
- 状態設計が先に固まる
- ViewModelに引きずられない
■ Previewを“コンポーネント設計”に使う
Composable分割とも強く関係します。
@Composable
fun ProfileHeader(...)
これ単体でPreviewできるか?
👉 YESなら良い設計
👉 NOなら依存が強すぎる
■ 実務でのPreview活用パターン
パターン① 状態網羅Preview
@Preview(name = "Empty")
@Preview(name = "Error")
@Preview(name = "Content")
パターン② ダークモード
@Preview(uiMode = UI_MODE_NIGHT_YES)
パターン③ サイズ違い
@Preview(widthDp = 320)
@Preview(widthDp = 600)
👉 UI仕様の検証ができる
■ Previewを壊すアンチパターン
❌ ViewModel依存
❌ remember乱用
❌ 外部状態依存
❌ Singletonアクセス
これらはすべて、
👉 Preview不能 = 設計不良
のサインです。
■ まとめ
Previewは単なる便利機能ではありません。
UI設計を可視化するツール
です。
重要なポイント
- PreviewできるUIは良い設計
- PreviewできないUIは責務が崩れている
- 状態を網羅すると設計の穴が見える
- Previewを先に書くと設計が安定する
Composeにおいて、
- 再利用できる
- テストしやすい
- バグりにくい
UIはすべて、
👉 PreviewしやすいUI
でもあります。

