課題
ActionBarで検索窓を設置したい。ただしデフォルトとはデザインが異なるため一部カスタマイズが必要である
対応
Googleからは検索用のWidgetとしてSearchViewが提供されている。
こちらをベースに必要な変更を行う
表示する
とりあえず表示できるようにする。app:actionViewClassを使ってSearchViewを明示するのと、Proguardを使っている場合には
難読化されないように設定が必要なので注意。
search_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/menu_search" android:icon="@drawable/ic_search" android:title="@string/label_search_title" app:actionViewClass="android.support.v7.widget.SearchView"/> </menu>
SearchFragment
override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) { inflater?.inflate(R.menu.search_menu, menu) }
proguard-rules.pro
## SearchView -keep class android.support.v7.widget.SearchView { *; }
常に開いた状態にする
なお、menu.xmlに色々書いても反映されなかったのでここからはコードで編集する。
findItemの引数はファイル名(ここではsearch_menu.xml)ではなくSearchViewのID(android:id="@+id/menu_search")の方なので注意。
val actionView = menu?.findItem(R.id.menu_search)?.actionView actionView?.let { it as SearchView setupSearchView(it) }
デフォルトオープンにはsetIconifiedByDefaultにfalseをセットすればよい。
searchView.setIconifiedByDefault(false)
入力イベントの処理
setOnQueryTextListenerを使う
searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener { override fun onQueryTextChange(newText: String?): Boolean { //TODO テキストが変更された } override fun onQueryTextSubmit(query: String?): Boolean { //TODO 検索ボタンが押下された } })
アイコンの差し替え
val mCollapsedIcon = view.findViewById<ImageView>(android.support.v7.appcompat.R.id.search_mag_icon) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { mCollapsedIcon.setImageDrawable(resources.getDrawable(R.drawable.ic_search, null)) }else { mCollapsedIcon.setImageDrawable(resources.getDrawable(R.drawable.ic_search)) }
非表示にしたい場合はnullをセットする
余白を削る
左側にマージンがあって気になる場合、search_edit_frameとsearch_mag_iconの余白を削る。それでも16dpほどどこかにあるが現時点では消し方不明。
//setup searchEditFrame searchEditFrame = view.findViewById(android.support.v7.appcompat.R.id.search_edit_frame) val frameLp = searchEditFrame?.layoutParams as LinearLayout.LayoutParams? frameLp?.let { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { frameLp.marginStart = 0 frameLp.leftMargin = 0 } else { frameLp.leftMargin = 0 } } //setup collapsedIcon collapsedIcon = view.findViewById(android.support.v7.appcompat.R.id.search_mag_icon) val iconLp = collapsedIcon?.layoutParams as LinearLayout.LayoutParams? iconLp?.let { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { iconLp.marginStart = 0 iconLp.leftMargin = 0 } else { iconLp.leftMargin = 0 } }
トラブルシューティング
setOnCloseListenerが呼ばれない
IconifiedByDefaultがfalseになっているとSearchViewはクローズされないのでsetOnCloseListenerは発生しない(SearchView.onCloseClickedを参照)。
setOnQueryTextListenerで代用