【2025年版】Jetpack Compose入門完全ガイド!Kotlinで始めるモダンなAndroid UI開発
AndroidアプリのUI開発が大きく変わろうとしています。Googleが推奨する次世代のUIツールキット「Jetpack Compose」をご存知でしょうか。
従来のXMLレイアウトと比べて、コードがシンプルになり、開発効率が大幅に向上します。この記事では、Jetpack Composeの基礎から実践的な使い方まで、初心者にもわかりやすく解説します。
Jetpack Composeとは?従来のXMLとの違い
Jetpack Composeは、Kotlinで宣言的にUIを構築できる、Androidの最新UIツールキットです。2021年に正式版がリリースされ、現在ではAndroid開発の標準となりつつあります。
従来のXML方式との主な違い
XMLレイアウトでは、レイアウトファイル(XML)とロジック(Kotlin/Java)が分離していました。これに対してJetpack Composeでは、UIもロジックもKotlinコードで記述します。これにより、コードの見通しが良くなり、保守性が向上します。
XMLではfindViewById()やDataBindingを使ってビューを操作していましたが、Composeでは状態管理が自動化されており、状態が変わると自動的にUIが更新されます(リコンポジション)。
また、XMLではネストが深くなりがちで可読性が低下しましたが、Composeでは関数の組み合わせで表現するため、コードがシンプルになります。
開発環境のセットアップ
Jetpack Composeを使うには、Android Studio Arctic Fox(2020.3.1)以降が必要です。最新版のAndroid Studioを使用することをおすすめします。
新規プロジェクトを作成する際、テンプレートから「Empty Activity」を選び、「Build configuration language」でKotlin DSLを選択します。
build.gradle.kts(Module)に以下の依存関係が含まれていることを確認しましょう。
android {
compileSdk = 34
defaultConfig {
minSdk = 21
targetSdk = 34
}
buildFeatures {
compose = true
}
composeOptions {
kotlinCompilerExtensionVersion = "1.5.8"
}
kotlinOptions {
jvmTarget = "1.8"
}
}
dependencies {
val composeBom = platform("androidx.compose:compose-bom:2024.02.00")
implementation(composeBom)
implementation("androidx.compose.ui:ui")
implementation("androidx.compose.material3:material3")
implementation("androidx.compose.ui:ui-tooling-preview")
implementation("androidx.activity:activity-compose:1.8.2")
debugImplementation("androidx.compose.ui:ui-tooling")
debugImplementation("androidx.compose.ui:ui-test-manifest")
}
基本の書き方:初めてのComposable関数
Jetpack ComposeではUIを「Composable関数」として定義します。@Composableアノテーションを付けた関数がUIコンポーネントになります。
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.Preview
@Composable
fun Greeting(name: String) {
Text(text = "こんにちは、${name}さん!")
}
@Preview(showBackground = true)
@Composable
fun GreetingPreview() {
Greeting(name = "太郎")
}
@Previewアノテーションを付けることで、Android Studioのプレビュー機能でUIを確認できます。コードを書きながらリアルタイムでUIを確認できるため、開発効率が大幅に向上します。
レイアウトの基本:Column、Row、Box
Jetpack Composeでは、レイアウトを構成する基本的なコンポーネントとして、Column(縦並び)、Row(横並び)、Box(重ね合わせ)があります。
import androidx.compose.foundation.layout.*
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
@Composable
fun LayoutExample() {
Column(
modifier = Modifier
.fillMaxSize()
.padding(16.dp),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(8.dp)
) {
Text("Column: 縦に並べる")
Row(
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
Button(onClick = { }) { Text("ボタン1") }
Button(onClick = { }) { Text("ボタン2") }
Button(onClick = { }) { Text("ボタン3") }
}
Box(
modifier = Modifier
.size(200.dp)
.padding(8.dp),
contentAlignment = Alignment.Center
) {
Text("Boxの中央")
}
}
}
Modifierを使うことで、サイズ、パディング、配置などのスタイルを柔軟に設定できます。Modifierは連鎖的に適用され、記述順序が重要です。
状態管理:remember と mutableStateOf
Jetpack Composeの最大の特徴は、状態管理の仕組みです。状態が変わると自動的にUIが再構築(リコンポジション)されます。
import androidx.compose.foundation.layout.*
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
@Composable
fun CounterApp() {
var count by remember { mutableStateOf(0) }
Column(
modifier = Modifier
.fillMaxSize()
.padding(16.dp),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
Text(
text = "カウント: $count",
style = MaterialTheme.typography.headlineMedium
)
Spacer(modifier = Modifier.height(16.dp))
Row(
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
Button(onClick = { count++ }) {
Text("増やす")
}
Button(onClick = { count-- }) {
Text("減らす")
}
Button(onClick = { count = 0 }) {
Text("リセット")
}
}
}
}
rememberは、リコンポジション時に値を保持するために使います。mutableStateOfは、変更可能な状態を作成します。byキーワードを使うことで、値の取得と設定が簡潔に書けます。
リストの表示:LazyColumnとLazyRow
長いリストを表示する場合、LazyColumnやLazyRowを使います。これらは必要な項目だけを描画するため、パフォーマンスが優れています。
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
data class Task(val id: Int, val title: String, val completed: Boolean)
@Composable
fun TaskList() {
val tasks = remember {
mutableStateListOf(
Task(1, "買い物に行く", false),
Task(2, "掃除をする", true),
Task(3, "レポートを書く", false),
Task(4, "プログラミング学習", false),
Task(5, "運動をする", true)
)
}
LazyColumn(
modifier = Modifier.fillMaxSize(),
contentPadding = PaddingValues(16.dp),
verticalArrangement = Arrangement.spacedBy(8.dp)
) {
items(tasks) { task ->
TaskItem(task = task)
}
}
}
@Composable
fun TaskItem(task: Task) {
Card(
modifier = Modifier.fillMaxWidth()
) {
Row(
modifier = Modifier.padding(16.dp),
verticalAlignment = Alignment.CenterVertically
) {
Checkbox(
checked = task.completed,
onCheckedChange = { }
)
Spacer(modifier = Modifier.width(8.dp))
Text(
text = task.title,
style = MaterialTheme.typography.bodyLarge
)
}
}
}
items関数を使うことで、リストの各要素に対してComposable関数を呼び出せます。キーを指定することで、リストの更新時のパフォーマンスを最適化できます。
ナビゲーション:画面遷移の実装
複数の画面を持つアプリでは、Jetpack Compose Navigationを使います。
まず、依存関係を追加します。
dependencies {
implementation("androidx.navigation:navigation-compose:2.7.6")
}
次に、ナビゲーションを実装します。
import androidx.compose.foundation.layout.*
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
@Composable
fun MyApp() {
val navController = rememberNavController()
NavHost(
navController = navController,
startDestination = "home"
) {
composable("home") {
HomeScreen(navController)
}
composable("detail/{itemId}") { backStackEntry ->
val itemId = backStackEntry.arguments?.getString("itemId")
DetailScreen(navController, itemId)
}
}
}
@Composable
fun HomeScreen(navController: NavHostController) {
Column(
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
Text("ホーム画面", style = MaterialTheme.typography.headlineMedium)
Spacer(modifier = Modifier.height(16.dp))
Button(onClick = { navController.navigate("detail/123") }) {
Text("詳細画面へ")
}
}
}
@Composable
fun DetailScreen(navController: NavHostController, itemId: String?) {
Column(
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
Text("詳細画面", style = MaterialTheme.typography.headlineMedium)
Text("Item ID: $itemId")
Spacer(modifier = Modifier.height(16.dp))
Button(onClick = { navController.popBackStack() }) {
Text("戻る")
}
}
}
NavHostでルーティングを定義し、navController.navigate()で画面遷移を行います。パラメータを渡すこともでき、動的なルーティングが可能です。
Material Design 3の活用
Jetpack ComposeはMaterial Design 3を標準でサポートしています。一貫性のある美しいUIを簡単に構築できます。
import androidx.compose.foundation.layout.*
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun Material3Example() {
var text by remember { mutableStateOf("") }
var expanded by remember { mutableStateOf(false) }
val options = listOf("オプション1", "オプション2", "オプション3")
Scaffold(
topBar = {
TopAppBar(
title = { Text("Material Design 3") },
colors = TopAppBarDefaults.topAppBarColors(
containerColor = MaterialTheme.colorScheme.primaryContainer
)
)
},
floatingActionButton = {
FloatingActionButton(onClick = { }) {
Text("+")
}
}
) { paddingValues ->
Column(
modifier = Modifier
.fillMaxSize()
.padding(paddingValues)
.padding(16.dp),
verticalArrangement = Arrangement.spacedBy(16.dp)
) {
OutlinedTextField(
value = text,
onValueChange = { text = it },
label = { Text("テキスト入力") },
modifier = Modifier.fillMaxWidth()
)
ExposedDropdownMenuBox(
expanded = expanded,
onExpandedChange = { expanded = it }
) {
OutlinedTextField(
value = options.firstOrNull() ?: "",
onValueChange = { },
readOnly = true,
label = { Text("ドロップダウン") },
modifier = Modifier
.menuAnchor()
.fillMaxWidth()
)
ExposedDropdownMenu(
expanded = expanded,
onDismissRequest = { expanded = false }
) {
options.forEach { option ->
DropdownMenuItem(
text = { Text(option) },
onClick = { expanded = false }
)
}
}
}
Card(
modifier = Modifier.fillMaxWidth()
) {
Column(
modifier = Modifier.padding(16.dp)
) {
Text(
"カードコンポーネント",
style = MaterialTheme.typography.titleLarge
)
Text(
"Material Design 3のカードです",
style = MaterialTheme.typography.bodyMedium
)
}
}
}
}
}
Scaffoldを使うことで、TopAppBar、FloatingActionButton、BottomNavigationなどを簡単に配置できます。Material Design 3のコンポーネントは、自動的にテーマカラーを適用します。
ViewModelとの連携
実際のアプリでは、ViewModelを使ってビジネスロジックと状態を管理します。
依存関係を追加します。
dependencies {
implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.7.0")
}
ViewModelを作成します。
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch
data class UiState(
val items: List<String> = emptyList(),
val isLoading: Boolean = false,
val error: String? = null
)
class MyViewModel : ViewModel() {
private val _uiState = MutableStateFlow(UiState())
val uiState: StateFlow<UiState> = _uiState.asStateFlow()
init {
loadItems()
}
private fun loadItems() {
viewModelScope.launch {
_uiState.value = _uiState.value.copy(isLoading = true)
try {
// データ取得処理(例:APIコール)
val items = listOf("アイテム1", "アイテム2", "アイテム3")
_uiState.value = _uiState.value.copy(
items = items,
isLoading = false
)
} catch (e: Exception) {
_uiState.value = _uiState.value.copy(
error = e.message,
isLoading = false
)
}
}
}
fun addItem(item: String) {
val currentItems = _uiState.value.items
_uiState.value = _uiState.value.copy(items = currentItems + item)
}
}
ComposeからViewModelを使います。
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.viewmodel.compose.viewModel
@Composable
fun MyScreen(viewModel: MyViewModel = viewModel()) {
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
Column(modifier = Modifier.fillMaxSize()) {
when {
uiState.isLoading -> {
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = androidx.compose.ui.Alignment.Center
) {
CircularProgressIndicator()
}
}
uiState.error != null -> {
Text("エラー: ${uiState.error}")
}
else -> {
LazyColumn(
contentPadding = PaddingValues(16.dp),
verticalArrangement = Arrangement.spacedBy(8.dp)
) {
items(uiState.items) { item ->
Card(modifier = Modifier.fillMaxWidth()) {
Text(
text = item,
modifier = Modifier.padding(16.dp)
)
}
}
}
}
}
}
}
collectAsStateWithLifecycle()を使うことで、StateFlowの値をComposeの状態として扱えます。ライフサイクルを考慮した収集が自動的に行われます。
パフォーマンス最適化のポイント
Jetpack Composeでパフォーマンスの良いアプリを作るためのポイントを紹介します。
不必要なリComposeを避ける
状態が変わると、その状態を使用しているComposable関数が再実行されます。不必要な再実行を避けるため、状態のスコープを適切に設定しましょう。
// 悪い例:全体が再実行される
@Composable
fun BadExample() {
var count by remember { mutableStateOf(0) }
Column {
Text("タイトル") // countが変わるたびに再実行される
Button(onClick = { count++ }) {
Text("Count: $count")
}
}
}
// 良い例:必要な部分だけ再実行される
@Composable
fun GoodExample() {
var count by remember { mutableStateOf(0) }
Column {
Text("タイトル") // 再実行されない
CounterButton(count) { count++ }
}
}
@Composable
fun CounterButton(count: Int, onClick: () -> Unit) {
Button(onClick = onClick) {
Text("Count: $count")
}
}
derivedStateOfの活用
計算コストの高い処理はderivedStateOfを使って最適化できます。
@Composable
fun OptimizedList() {
val items by remember { mutableStateOf(List(100) { it }) }
val filteredItems by remember {
derivedStateOf {
items.filter { it % 2 == 0 } // 偶数のみ
}
}
LazyColumn {
items(filteredItems) { item ->
Text("Item: $item")
}
}
}
LazyListのキーを指定
リストアイテムにキーを指定することで、更新時のパフォーマンスが向上します。
LazyColumn {
items(
items = taskList,
key = { task -> task.id }
) { task ->
TaskItem(task)
}
}
まとめ
Jetpack Composeは、Androidアプリ開発を大きく進化させる技術です。この記事で解説した内容をまとめます。
Jetpack Composeでは、UIをKotlinコードで宣言的に記述でき、XMLレイアウトよりシンプルで保守性が高くなります。状態管理が自動化されており、状態が変わると自動的にUIが更新されます。Column、Row、Boxなどの基本コンポーネントを組み合わせてレイアウトを構築し、LazyColumnやLazyRowで効率的にリストを表示できます。NavigationやViewModelとの連携も簡単で、Material Design 3を標準サポートしています。
Jetpack Composeは学習コストがありますが、一度慣れると従来の方法より圧倒的に効率的に開発できます。ぜひあなたも次のプロジェクトでJetpack Composeを試してみてください。
この記事が役に立ちましたら、ぜひシェアしてください。質問やコメントもお待ちしています!

ディスカッション
コメント一覧
まだ、コメントがありません