Navigation + BottomNavigationでタブの遷移先を条件に合わせて変更する
本稿は2021年に執筆したものをZennに移行したものです。
NavigationとBottomNavigationを組み合わせた場合、各タブの遷移先は以下のようなmenu xmlに記述したものに固定される。
<?xml version="1.0" encoding="utf-8"?>
<menu
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
>
<item
android:id="@+id/fragment_foo"
android:title="Foo"
/>
<item
android:id="@+id/fragment_bar"
android:title="Bar"
/>
</menu>
タブ Bar の遷移先を条件に合わせて変更する方法について考える。
タブ Bar をタップすると、まずBarSetupFragmentに遷移し、そこでなにかしらの設定を完了させて以降、タブ Bar をタップするとBarFragmentに遷移するとする。
GatewayFragmentを作成するパターン
上述したように、各タブの遷移先はmenu xmlに記述したものに固定されるので、フラグを読み取りBarSetupFragmentかBarFragmentにnavigateしてくれるBarGatewayFragmentを実装し、menu xmlにはBarGatewayFragmentを記述する方法をとってみる。
<?xml version="1.0" encoding="utf-8"?>
<menu
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
>
<item
android:id="@+id/fragment_foo"
android:title="Foo"
/>
<item
android:id="@+id/fragment_bar_gateway"
android:title="Bar"
/>
</menu>
class BarGatewayFragment : Fragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val direction = if (isSetupDone)
BarGatewayFragmentDirections.toBar()
else
BarGatewayFragmentDirections.toBarSetup()
findNavController().navigate(direction)
}
}
このままだと、BarGatewayFragmentからBarFragment/BarSetupFragmentに遷移した際にBackStackにBarGatewayFragmentが残ってしまうので、navigation xmlにおけるBarGatewayFragmentの各actionは以下のようにし、BarGatewayFragmentがBackStackから消えるようにする。
<fragment
android:id="@+id/bar_gateway"
android:name="io.moyuru.myapplication.GatewayFragment"
>
<action
android:id="@+id/to_bar"
app:destination="@id/bar"
app:popUpTo="@id/bar_gateway"
app:popUpToInclusive="true"
/>
<action
android:id="@+id/to_bar_setup"
app:destination="@id/bar_setup"
app:popUpTo="@id/bar_gateway"
app:popUpToInclusive="true"
/>
</fragment>
ちなみに、サンプルコードではonCreate内でNavController#navigateをcallしているが、onAttach ~ onStartまでのどこのタイミングが一番最適なのかはわかっていない。
とりあえずこの方法で進めてみようと思っている。
ボツにしたパターン
BottomNavigationのmenuを随時clearしてinflateし直すパターン。
地雷臭がぷんぷんしたので試してすらいない。
bottomNavigation.menu.clear()
bottomNavigation.inflateMenu(...)
Discussion