【正社員】還元率83%【フリーランス】マージン一律5万円で案件をご紹介させていただきます。 詳細はこちら

【Android】<Kotlin>Navigation Composeで戻るボタンを実装する方法&挙動をカスタマイズする方法(アプリ内戻るボタン + 端末自体の戻るボタン)

【Android】<Kotlin>Navigation Composeで戻るボタンを実装する方法&挙動をカスタマイズする方法(アプリ内戻るボタン + 端末自体の戻るボタン)
すだ

みなさまこんにちは〜!
メモリアインクのすだです。

今回は、Navigation Composeを利用した「戻るボタン」の実装とカスタマイズ、さらには端末自体の戻るボタンのカスタマイズについて、実際のコードを用いて解説していきます。

この記事を読んでわかること…
・Navigation Composeを利用した戻るボタンの実装
・アプリ内戻るボタン&端末自体の戻るボタン それぞれの制御処理

目次

環境

  • Kotlin (ver 1.9.0)
  • Android Studio (Giraffe | 2022.3.1 Patch 3)

Navigation Composeとは?

Navigation Compose は、Jetpack Compose で画面遷移(Navigation)を行うためのライブラリです。
従来の XML + Fragment ベースの NavController を、Compose UI の世界に合わせて使えるようにしたものです。

val navController = rememberNavController()
NavHost(navController, startDestination = "home") {
    composable("home") { HomeScreen(navController) }
    composable("settings") { SettingsScreen(navController) }
}

Navigation Composeのより詳しい内容については、以下の記事にまとめています。
ぜひ併せてご覧ください。

Navigation Composeを利用して、アプリ内に「戻るボタン」を実装する方法

基本的な 「画面左上にある (一つ前の画面に)戻るボタン」の実装についてです。

Jetpack Compose + Navigation Compose で実現する場合は、
NavController.popBackStack() を使うのが正解です。

これは「ナビゲーションスタックから現在の画面を削除して1つ前の画面に戻る」処理です。

以下のように TopAppBar に戻るボタンを追加し、その onClick 内で navController.popBackStack() を呼びます。

@Composable
fun DetailScreen(navController: NavController) {
    Scaffold(
        topBar = {
            TopAppBar(
                title = { Text("詳細画面") },
                navigationIcon = {
                    IconButton(onClick = {
                        navController.popBackStack() // ← 一つ前の画面に戻る
                    }) {
                        Icon(
                            imageVector = Icons.Default.ArrowBack,
                            contentDescription = "戻る"
                        )
                    }
                }
            )
        }
    ) {
        Text("ここは詳細画面です", modifier = Modifier.padding(it))
    }
}

TopAppBarのnavigationIcon は TopAppBarの左側に表示されるナビゲーション用アイコン を定義する場所です。

そしてnavController.popBackStack() は、
Navigation Compose が内部で保持しているスタック(履歴)から現在の画面を削除し、前の画面をトップにする処理を行なってくれます。

つまり、HomeScreen → DetailScreen と遷移してきた場合、
popBackStack() を呼べば DetailScreen を閉じて HomeScreen に戻る、という自然な挙動になります。

戻るボタンの制御

「TopAppBarに作成した アプリ内の戻るボタン」の制御

これは、onClick内にコードを書くことで実現できます。
(たとえば、戻るボタンタップで確認ダイアログが出るなど)

topBar = {
        TopAppBar(
            title = { Text("確認付き戻る") },
            navigationIcon = {
                IconButton(onClick = { showDialog = true }) { // ← ここでトリガー
                    Icon(
                        imageVector = Icons.Default.ArrowBack,
                        contentDescription = "戻る"
                    )
                }
            }
        )
    }

上記のようにTopAppBar内に戻るボタンを作成した後、

if (showDialog) {
    AlertDialog(
        onDismissRequest = { showDialog = false },
        title = { Text("終了しますか?") },
        text = { Text("この画面を終了してもよろしいですか?") },
        confirmButton = {
            TextButton(onClick = {
                showDialog = false
                navController.popBackStack() // 実際に戻る
            }) {
                Text("はい")
            }
        },
        dismissButton = {
            TextButton(onClick = {
                showDialog = false // stay
            }) {
                Text("キャンセル")
            }
        }
    )
}

このようにダイアログを出す処理を書いて、ダイアログ内のボタンタップ処理の中でnavController.popBackStack()を書くといったような実装が可能です。

端末自体の戻るボタン」の制御

一方、「端末自体の戻るボタン」の制御も行いたい場合、これもアプリ側で制御する必要が出てきます。

この場合、Composeでは、androidx.activity.compose.BackHandlerを使って戻るボタンを制御できます。

BackHandlerの使い方

基本的には以下のように書きます。

BackHandler(enabled = true) {
    // 戻るボタンが押されたときの処理を書く
}

この BackHandler は、Compose UI の中でのみ有効です

実際に、「戻るボタンタップで確認ダイアログを出す」という実装を行なってみたいと思います。▼

@Composable
fun ExitConfirmationScreen(navController: NavController) {
    var showDialog by remember { mutableStateOf(false) }

    BackHandler(enabled = true) {
        showDialog = true
    }

    if (showDialog) {
        AlertDialog(
            onDismissRequest = { showDialog = false },
            title = { Text("終了しますか?") },
            confirmButton = {
                TextButton(onClick = { navController.popBackStack() }) {
                    Text("はい")
                }
            },
            dismissButton = {
                TextButton(onClick = { showDialog = false }) {
                    Text("キャンセル")
                }
            }
        )
    }

    Text("この画面から戻るときは確認が出ます")
}

BackHandler { ... } は、端末の戻るボタン(ハードキーやジェスチャー)をユーザーが押したときに発火するCompose専用のハンドラです。

enabled パラメータには、「この BackHandler を有効にするかどうか」という意味があります。
enabled = trueの場合は処理の発火が有効になりますが、enabled = false のときは、BackHandler は存在していても無視される状態になります。

よくある使われ方としては、

val canHandleBack by remember { mutableStateOf(true) }

BackHandler(enabled = canHandleBack) {
    // 戻るボタンが押されたときの処理
}

こうすると、canHandleBack の状態によって 戻る動作のオンオフを切り替えて
たとえばダイアログが表示中のときだけ BackHandler を有効にしたいときなどに便利になるようにする という実装です。

まとめ

おつかれさまでした。いかがでしたでしょうか!

戻るボタンはよく実装するパーツのうちの一つであるかつ、
アプリ内の戻るボタンタップ時に何か処理を加える時には 端末自体の戻るボタンにも同様に処理を加える必要がある場合が多いかと思うので
ぜひ覚えて使いこなしてください。

すだ

技術者としてのキャリアパスを次のレベルへと進めたい皆様、
未経験からIT・Webエンジニアを目指すなら【ユニゾンキャリア】
を通じて、
自分の市場価値をさらに向上させてみませんか?

それではまた次回の記事でお会いしましょう!

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

弊社テックブログをご愛読いただきありがとうございます。
当テックブログを運用している株式会社メモリアインクは、
【正社員】還元率83%
【フリーランス】マージン一律5万円で案件のご紹介
と、エンジニアの皆様に分かりやすい形で稼げる仕組みを構築し提供させていただいております。

コメント

コメントする

目次