Composable FunctionはJetpack Composeにおけるユーザーインターフェースの基本単位であり、画面の一部がどのように見えて動作すべきかを定義します。それぞれの関数は@Composable注釈が付けられ、Composeが依存関係をトラックし、データが変わったときにUIを自動的に再構築できるようにする特殊なコンテキストで実行されます。Google Android Developers, 2026によると、Composable関数の正しい構築は、アプリケーションのパフォーマンスと再構成の効率に直接影響します。
メインポイント
Composable Functionは、@Composable注釈が付けられたKotlin言語の関数で、宣言的な方法でユーザーインターフェースの一部を記述します。JavaコードやXMLマークアップを通じてViewオブジェクトを作成および構成するかわりに、開発者はデータの各状態に对してUIがどのように見えるべきかをシンプルに書くだけです。
Composable関数と伝統的なAndroid Viewシステムの主な違いは、更新モデルにあります。クラシックなアプローチでは、開発者が手動でfindViewByIdを呼び出し、setTextでテキストを変更し、setVisibilityで可視性を管理していました。Composable Functionはこのルーチンからあなたを解放します:データが変わると、システム自身がどの関数を再構成すべきかを判断し、それらのみを実行します。
Kotlinコンパイラは、@Composable注釈を処理するときに、関数をコンポジションメカニズムに統合する追加コードを生成します。このコードには、スロット(現在のUIツリー内の各Composable関数の状態と引数を保管する特殊なメモリセル)への読み込みと書き込みが含まれます。この統合により、Composeはどの関数がどのデータに依存しているかを知ることができます。
Composable関数の構文は極めて簡潔です:funキーワードの前に@Composableを追加するだけです。関数は任意の引数を受け入れ、ボディ内に他のComposable呼び出しを含め、条件付きUIレンダリングのためにKotlinの構造(条件、ループ、when式)を使用できます。
@Composable
fun ProductItem(
product: Product,
modifier: Modifier = Modifier,
onAddToCart: () -> Unit
) {
Card(modifier = modifier.padding(8.dp)) {
Row(modifier = Modifier.fillMaxWidth().padding(12.dp),
verticalAlignment = Alignment.CenterVertically) {
Column(modifier = Modifier.weight(1f)) {
Text(text = product.name, style = MaterialTheme.typography.titleMedium)
Text(text = "${product.price}", color = MaterialTheme.colorScheme.primary)
}
Button(onClick = onAddToCart) {
Text("カートに追加")
}
}
}
}
この例では、ProductItem Composable関数がProductオブジェクト、モディファイア、およびコールバックを受け入れます。3つの引数はすべて不変であり、再構成中の予測可能な動作を保証します。モディファイアはデフォルト値を持つ引数として渡されます。これは、呼び出し側がパディングやサイズをカスタマイズできるようにする標準的なパターンです。
Composable関数の内部では、ビルトインのMaterial Designコンポーネント(Text, Button, Card, TextField)や基本的なプリミティブ(Canvas, Layout)が使用されます。各コンポーネントは、外観と動作を構成するための引数、およびmodifier引数を通じて複数のモディファイアを受け入れます。
モディファイアは、コンポーネントのサイズ、位置、イベント処理、外観を変更する関数のチェーンです。チェーンにおけるモディファイアの順序は重要です:clickable.semanticsはsemantics.clickableとは異なる動作をし、padding.backgroundはパディングを含むエリアと背景の両方を描画するため、デザイン上重要です。
Composable関数の内部では、ifやwhen条件を使ってUIの一部を条件付きでレンダリングしたり、forループで動的なリストを扱ったりできます。Kotlinは完全なプログラミング言語であるため、これらの構造は自然に動作します。ただし、条件やループがComposable関数の呼び出しを含む場合、それらも再構成に参加することを記憶することが重要です。
@Composable
fun ProductList(
products: List<Product>,
modifier: Modifier = Modifier
) {
LazyColumn(modifier = modifier) {
items(products, key = { it.id }) { product ->
ProductItem(
product = product,
onAddToCart = { /* add to cart */ }
)
}
}
}
複数のComposable関数を使用した商品検索画面の例を考えてみましょう。ここでは、状態を持つ入力フィールド、リストのフィルタリング、空の結果の処理、ローディングといった典型的なパターンが示されています。
data class Product(
val id: String,
val name: String,
val price: Double,
val category: String
)
@Composable
fun SearchScreen() {
var query by remember { mutableStateOf("") }
val products = remember(query) { getFilteredProducts(query) }
Column(modifier = Modifier.fillMaxSize().padding(16.dp)) {
OutlinedTextField(
value = query,
onValueChange = { query = it },
label = { Text("商品を検索") },
modifier = Modifier.fillMaxWidth()
)
Spacer(modifier = Modifier.height(16.dp))
when (products) {
is Loading -> CircularProgressIndicator()
is Empty -> Text("結果が見つかりませんでした")
is Result -> LazyColumn {
items(products.items, key = { it.id }) { product ->
ProductItem(product = product, onAddToCart = {})
}
}
}
}
}
この例は、検索クエリの状態を保存するためのremember、キーでフィルタリングするためのrenember(query)、3つのUI状態のためのwhen、効率的なリスト表示のためのLazyColumnなど、いくつかのイディオムを同時に示しています。これらの各イディオムは、Composeアプリケーションを開発する実践的な経験の結果です。
Composable関数は、通常のKotlin関数と同様に引数を受け入れますが、1つ重要な違いがあります:引数には、@Composable注釈が付いたlambdaを通じて渡された別のComposable関数を指定できます。このメカニズムをSlot APIと呼び、再利用可能なコンテナを作成するための主要パターンです。
Slot APIは、伝統的なViewシステムでViewGroupとプログラム的な子Viewの追加によって解決されていた問題を解決します。addViewメソッドの代わりに、Composeはcontent lambda(@Composable () -> Unit型の最終引数)を使用します。呼び出し側はこのlambdaに任意のUIを渡し、コンテナはそのレイアウトのみを定義します。
Composable関数の引数にはデフォルト値を設定でき、異なるコンテキストでの使用が簡単になります。推奨されるのは、関数が任務を実行できない引数のみを必須にし、それ以外には合理的なデフォルト値を指定することです。
| 引数 | 型 | 例 |
|---|---|---|
| 必須 | 任意の型 | name: String |
| 任意 | デフォルト値付き | modifier: Modifier = Modifier |
| Content | @Composable () -> Unit | content: @Composable () -> Unit |
| Callback | @ComposableなしのLambda | onClick: () -> Unit |
Composeコミュニティでは、Composable関数をより読みやすく予測可能にするいくつかの確立したイディオムが登場しています。まず、State Hoisting:状態を一つ上のレベルに揚げ、Composable関数がそれを引数で受け取ります。これにより関数がピュアになり、異なるコンテキストで再利用できます。
2つ目のイディオムはEvent-driven引数です。Composable関数にViewModelやuseCaseを渡す代わりに、特定のコールバック(onSave, onDelete, onNavigateToDetail)のみを渡します。これにより結合を低減し、テストが簡単になります。
3つ目のイディオムはCompositionLocalで、コンポジションツリーを通じて共有データを渡すためのものです。テーマ、スクリーン密度、現在のRouteはすべてCompositionLocalを通じて渡され、数十のComposable関数を歩いて引数チェーンを回避します。ただし、CompositionLocalを使い過ぎてはいけません:明示的な引数はいつでも暗黙的な依存関係より優先されます。
// State Hoisting: 状態が親関数に揚げられた
@Composable
fun CounterDisplay(
count: Int,
onIncrement: () -> Unit
) {
Column(horizontalAlignment = Alignment.CenterHorizontally) {
Text(text = "カウンタ: $count", style = MaterialTheme.typography.headlineLarge)
Button(onClick = onIncrement) {
Text("+1")
}
}
}
// State Hoistingの使い方
@Composable
fun CounterScreen() {
var count by remember { mutableStateOf(0) }
CounterDisplay(
count = count,
onIncrement = { count++ }
)
}
よくある質問
はい、returnは許されていますが、注意が必要です。Composeは個々の関数のレベルで再構成を最適化しており、早期のreturnはこの最適化を壊す可能性があります。関数ボディ内で条件演算子ifまたはwhenを使用することが推奨されます。
Kotlinでは、Unitはシングルトンオブジェクトであり、空の型ではありません。Composable関数はUnitを返しますが、これは技術的にはUnitオブジェクト自体を返すことを意味します。ただし、実際にはこれは重要ではありません。
変更可能なコレクションを渡すことはできますが、良いプラクティスではありません。コレクションが変わっても、オブジェクト参照が変わらないためComposeはそれを検知できません。トラックされた変更には、不変リストまたはmutableStateListOfを使用します。
デバッグには、Layout Inspectorを備えたAndroid Studioを使用します。現在のComposable関数ツリー、引数の値、再構成の理由が表示されます。通常のKotlinデバッガーも動作します。
Composable関数はいつもUnitを返すため、戻り値の型は指定されません。別の型を返そうとすると、@Composable注釈が非Unitの戻り値の型と不兼容であるため、コンパイルエラーが発生します。
まとめ
ターンキー方式のモバイルアプリケーションを開発します
IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。