2019/12/23 追記
OnBackPressedDispatcher.addCallback()
を呼ぶタイミングに関する問題があったのでコード例を修正。
問題に関する詳細は 別の記事 にまとめた。
やりたいこと
- 必要があればFragment側で「戻るボタン」押下を処理する(Activityには処理を伝搬させない)
- Fragment側で処理する必要がないときはActivityが処理する。
これまで
これまで、Fragmentには戻るボタンのリスナが無かったので次のように自分でそれっぽいものを用意する必要があった。
Fragment用にインターフェースを用意して、
interface BackPressable {
/** 処理した場合はtrueを返す */
fun onBackPressed() : Boolean
}
ActivityのonBackPressed()メソッドで例えばこんな感じにしていた。
override fun onBackPressed() {
val fragment = supportFragmentManager.findFragmentById(containerId)
val handled =
if (fragment is BackPressable) {
fragment.onBackPressed()
}
else false
if (!handled) {
super.onBackPressed()
}
}
これから
androidx.fragment:fragment-ktx:1.2.0からは次のようにできる。
まだ安定版ではなくちょくちょく実装に変更が加えられているようなので、これからまた変わるかもしれない。
build.gradle
implementation "androidx.fragment:fragment-ktx:1.2.0-rc04"
class HogeActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
// ~~~ 省略 ~~~
if (savedInstanceState != null) {
onBackPressedDispatcher.addCallback(this) {
// Activityでの戻るボタン処理
}
}
// ~~~ 省略 ~~~
}
}
class HogeFragment : Fragment() {
override fun onResume() {
super.onResume()
requireActivity().onBackPressedDispatcher.addCallback(this) {
// Fragmentでの戻るボタン処理
}
}
}
addCallback(owner ,enabled, onBackPressed)
にはそれぞれ次のような引数が設定でき、enabledは省略してもいい。
- owner: LifecycleOwner? … ライフサイクル監視対象
- enabled: Boolean … このコールバックが有効か否か
- onBackPressed: OnBackPressedCallback.()->Unit … 「戻るボタン」が押されたときに行う処理
addCallbackは追加したOnBackPressedCallbackを返すので、これを使って動的にコールバックの有効無効を切り替えることができる。
val callback = requireActivity().onBackPressedDispatcher.addCallback(this) {
// 「戻るボタン」を一回押すとこのコールバックを無効にする
isEnabled = false
}
callback.isEnabled = true
コールバックは最も新しく追加されたisEnabled == true
なものが呼ばれる。
なので、フラグメント側で戻る処理が必要なくなったら忘れずisEnabled = false
しないといつまで経ってもActivityに処理が渡らないので注意。