0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【Android】Fragment切り替えの時にアプリバーを更新する

Posted at

概要

FragmentTransactionreplace()からadd()に変更した際、Fragment遷移時に更新していたアプリバーのタイトルやメニューボタン等が更新されなくなった。
add()の場合でもアプリバーを更新できる方法をまとめる。この記事ではonBackStackChangedListenerを使っている。

Fragment遷移時にアプリバーの要素を更新する

MainActivity.kt
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()
        }
    }
}
BaseFragment.kt
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ごとのタイトルやメニュー等をセットする。

HomeFragment.kt
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)
            }
        }
    }
}
SampleFragment.kt
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)
            }
        }
    }
}

update_actionbar_home.png update_actionbar_sample.png
これで、Fragment遷移の時にアプリバーのタイトルやメニューなどの要素が更新されるようになっ……あれ?

update_actionbar_sample_increase_icon.png
update_actionbar_sample_increase_icon_line (3).png
お分かりいただけただろうか……

しかもこの「次へ」ボタンも押せるため、SampleFragmentとそのメニューアイコンが無限に増える。無限ループって怖くね?
update_actionbar_sample_increase_icon_4.png   update_actionbar_sample_increase_icon_infinite.png

表示しているFragmentのメニューのみを表示する

SampleFragmentに遷移したにもかかわらず、HomeFragmentのメニューが表示されたままになってしまっている。
そこで、現在表示しているFragmentのメニューのみを表示したい。

画面遷移をする時に、this.setHasOptionsMenu(false)で遷移前のFragmentのメニューを隠すことにする。

HomeFragment.kt
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)
            }
        }
    }
}

これで、違うメニューが表示されなくなった。
update_actionbar_sample_success.png

まとめ

  • onBackStackChangedListenerを使って、Fragment遷移時にアプリバーの要素を更新した。
  • this.setHasOptionsMenu(false)でFragment遷移時に遷移前のFragmentのメニューを隠した。
0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?