概要
FragmentTransactionをreplace()
からadd()
に変更した際、Fragment遷移時に更新していたアプリバーのタイトルやメニューボタン等が更新されなくなった。
add()
の場合でもアプリバーを更新できる方法をまとめる。この記事ではonBackStackChangedListener
を使っている。
Fragment遷移時にアプリバーの要素を更新する
class MainActivity : AppCompatActivity() {
val activeFragment: BaseFragment?
get() {
val fragment = supportFragmentManager.findFragmentByTag("baseFragment")
return fragment as? BaseFragment
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
... (略) ...
// BackStackが変更された時
supportFragmentManager.addOnBackStackChangedListener {
activeFragment?.updateActionBar()
}
}
}
abstract class BaseFragment : Fragment() {
... (略) ...
override fun onCreateView(inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?): View? {
updateActionBar()
return null
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
super.onCreateOptionsMenu(menu, inflater)
}
open fun updateActionBar() {
appActivity?.supportActionBar?.apply {
setTitle("")
// 戻るボタンを表示するかどうか
setDisplayHomeAsUpEnabled(showsBackBarButton)
setBackgroundDrawable(ColorDrawable(Color.parseColor("#008577")))
}
}
}
BackStackが変更された時に、Fragment遷移後にアプリバーを更新する(activeFragment
は遷移後のFragmentになる)。
各FragmentはBaseFragment
を継承して作成し、updateActionBar()
をオーバーライドして、Fragmentごとのタイトルやメニュー等をセットする。
class HomeFragment : BaseFragment() {
... (略) ...
override fun updateActionBar() {
super.updateActionBar()
this.setHasOptionsMenu(true)
appActivity?.supportActionBar?.title = "ホーム"
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
super.onCreateOptionsMenu(menu, inflater)
inflater.inflate(R.menu.home_menu, menu)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return when (item.itemId) {
R.id.action_next -> {
// SampleFragmentへ遷移するコード
true
}
else -> {
super.onOptionsItemSelected(item)
}
}
}
}
class SampleFragment : BaseFragment() {
... (略) ...
override fun updateActionBar() {
super.updateActionBar()
this.setHasOptionsMenu(true)
appActivity?.supportActionBar?.apply {
setTitle("サンプル")
setBackgroundDrawable(ColorDrawable(Color.RED))
}
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
super.onCreateOptionsMenu(menu, inflater)
inflater.inflate(R.menu.sample_menu, menu)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return when (item.itemId) {
R.id.action_sample -> {
// icon pressed
true
}
else -> {
super.onOptionsItemSelected(item)
}
}
}
}
これで、Fragment遷移の時にアプリバーのタイトルやメニューなどの要素が更新されるようになっ……あれ?
しかもこの「次へ」ボタンも押せるため、SampleFragmentとそのメニューアイコンが無限に増える。無限ループって怖くね?
表示しているFragmentのメニューのみを表示する
SampleFragmentに遷移したにもかかわらず、HomeFragmentのメニューが表示されたままになってしまっている。
そこで、現在表示しているFragmentのメニューのみを表示したい。
画面遷移をする時に、this.setHasOptionsMenu(false)
で遷移前のFragmentのメニューを隠すことにする。
class HomeFragment : BaseFragment() {
... (略) ...
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return when (item.itemId) {
R.id.action_next -> {
// このFragmentのメニューを隠す
this.setHasOptionsMenu(false)
// SampleFragmentへ遷移するコード
true
}
else -> {
super.onOptionsItemSelected(item)
}
}
}
}
まとめ
-
onBackStackChangedListener
を使って、Fragment遷移時にアプリバーの要素を更新した。 -
this.setHasOptionsMenu(false)
でFragment遷移時に遷移前のFragmentのメニューを隠した。