AndroidでActionBar
にSearchView
のようなアクションビュークラスを使用してる時に発生するバグもどきに対する備忘録です。
問題の詳細
以下のコードでSearchView
が開かれた(expand)状態でオーバーフローメニューをタップしたりDialogFragment
を開いたりすると表示されていたアクションボタンがオーバーフローメニューに移り、更にその状態でSearchView
を閉じると表示されていたSearchView
を含めた全てのアクションボタンが消える。
menu_main.xml
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/search_bar"
android:icon="@drawable/ic_search"
android:title="search"
app:actionViewClass="androidx.appcompat.widget.SearchView"
app:iconTint="?attr/colorOnPrimarySurface"
app:showAsAction="ifRoom|collapseActionView" />
<item
android:id="@+id/button1"
android:icon="@drawable/ic_button1"
android:title="button1"
app:iconTint="?attr/colorOnPrimarySurface"
app:showAsAction="ifRoom" />
<item
android:id="@+id/button2"
android:icon="@drawable/ic_button2"
android:title="button2"
app:iconTint="?attr/colorOnPrimarySurface"
app:showAsAction="ifRoom" />
<item
android:id="@+id/settings"
android:title="settings"
app:showAsAction="never" />
</menu>
MainActivity.kt
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.menu_main, menu)
return true
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return when (item.itemId) {
R.id.button1, R.id.button2, R.id.settings -> true
else -> super.onOptionsItemSelected(item)
}
}
}
問題の原因
SearchView
を開いている時にonPrepareOptionsMenu
が行われると
「SearchView
が邪魔でアクションボタンが表示できない→仕方がないのでアクションボタンをオーバーフローメニューに入れる→SearchView
が閉じられる→オーバーフローメニューに入れられたやつがどっかいく (何故?) 」という流れになるっぽい。
解決策
素直に「menu_main.xml」のifRoom
を全てalways
またはnever
にすれば解決する。
menu_main.xml
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/search_bar"
android:icon="@drawable/ic_search"
android:title="search"
app:actionViewClass="androidx.appcompat.widget.SearchView"
app:iconTint="?attr/colorOnPrimarySurface"
- app:showAsAction="ifRoom|collapseActionView"
+ app:showAsAction="always|collapseActionView" />
<item
android:id="@+id/button1"
android:icon="@drawable/ic_button1"
android:title="button1"
app:iconTint="?attr/colorOnPrimarySurface"
- app:showAsAction="ifRoom"
+ app:showAsAction="always" />
<item
android:id="@+id/button2"
android:icon="@drawable/ic_button2"
android:title="button2"
app:iconTint="?attr/colorOnPrimarySurface"
- app:showAsAction="ifRoom"
+ app:showAsAction="never" />
<item
android:id="@+id/settings"
android:title="settings"
app:showAsAction="never" />
</menu>
ただし、どうしてもifRoom
を変えたくないという場合はonPrepareOptionsMenu
をオーバーライドしてSearchView
を無理やり閉ざしてやればいい。
MainActivity.kt
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.menu_main, menu)
return true
}
+ override fun onPrepareOptionsMenu(menu: Menu): Boolean {
+ menu.findItem(R.id.search_bar).collapseActionView()
+ return true
+ }
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return when (item.itemId) {
R.id.button1, R.id.button2, R.id.settings -> true
else -> super.onOptionsItemSelected(item)
}
}
}