#インクリメンタルサーチとは
そもそもインクリメンタルサーチとはなんぞや
インクリメンタルサーチ(Wikipedia)
アプリケーションにおける検索方法のひとつ。 検索したい単語をすべて入力した上で検索するのではなく、入力のたびごとに即座に候補を表示させる。 逐語検索、逐次検索とも。
アプリでよく使われている検索方法ですね。
早速やってみます。
#準備
記事ではRecyclerViewを使用して、ツールバーに検索ボックス(SearchView)を実装してみます。
app/build.gradle
dependencies {
compile 'com.android.support:recyclerview-v7:26.1.0'
}
styles.xml
<style name="AppTheme" parent="android:Theme.Material.Light.NoActionBar">
/// 省略
</style>
#SearchView
検索用のメニューを作成します。
search.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/menu_search"
android:title="検索"
android:actionViewClass="android.widget.SearchView"
android:showAsAction="always"/>
</menu>
SearchView.OnQueryTextListenerから検索文字を取得します。
val searchView = menu.findItem(R.id.menu_search).actionView as SearchView
searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
.
.
.
今回はインクリメンタルで検索したいので、onQueryTextChangeから
検索文字が変更されるたびに文字を受け取るようにします。
ItemListActivity.kt
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
menuInflater.inflate(R.menu.search, menu)
if (menu != null) {
val searchView = menu.findItem(R.id.menu_search).actionView as SearchView
searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(text: String?): Boolean {
// 検索キーが押下された
Log.d(TAG, "submit text: $text")
return false
}
override fun onQueryTextChange(text: String?): Boolean {
// テキストが変更された
Log.d(TAG, "change text: $text")
val itemListFragment = fragmentManager.findFragmentById(R.id.container)
if (itemListFragment is ItemListFragment && text != null) {
itemListFragment.searchRequest(text)
}
return false
}
})
}
return super.onCreateOptionsMenu(menu)
}
検索文字を受け取ったら検索対象にフィルターをかけて更新します。
ItemListFragment.kt
fun searchRequest(text: String) {
val adapter = adapter
if (adapter != null) {
adapter.data = items.filter { it.contains(text) }
adapter.notifyDataSetChanged()
}
}
#実行結果
テキストの入力の度に検索結果を表示させることができました
#コード
以下、最終的なソースコードです。
レイアウトは各々で作成してみてください。
ItemListAdapter.kt
class ItemListAdapter(private val context: Context,
var data: List<String>) : RecyclerView.Adapter<ItemListAdapter.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): ViewHolder {
val inflater = LayoutInflater.from(context)
return ViewHolder(inflater.inflate(R.layout.item, parent, false))
}
override fun getItemCount(): Int {
return data.size
}
override fun onBindViewHolder(holder: ViewHolder?, position: Int) {
holder?.title = data[position]
}
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
private var titleTextView: TextView = itemView.findViewById(R.id.title_text)
var title: String
get() = titleTextView.text.toString()
set(value) {
titleTextView.text = value
}
}
}
ItemListFragment.kt
class ItemListFragment : Fragment() {
private var mView: View? = null
private var recyclerView: RecyclerView? = null
private val items: MutableList<String> = mutableListOf()
private var adapter: ItemListAdapter? = null
init {
for (i in 1..100) {
items.add("アイテム$i")
}
}
override fun onCreateView(inflater: LayoutInflater?,
container: ViewGroup?,
savedInstanceState: Bundle?): View {
super.onCreateView(inflater, container, savedInstanceState)
mView = inflater!!.inflate(R.layout.fragment_item_list, container, false)
val linerLayoutManager = LinearLayoutManager(mView!!.context)
recyclerView = mView!!.findViewById(R.id.recycler_view)
recyclerView!!.layoutManager = linerLayoutManager
val dividerDecoration = DividerItemDecoration(recyclerView!!.context, linerLayoutManager.orientation)
recyclerView!!.addItemDecoration(dividerDecoration)
return mView!!
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
adapter = ItemListAdapter(mView!!.context, items)
recyclerView!!.adapter = adapter
}
fun searchRequest(text: String) {
val adapter = adapter
if (adapter != null) {
adapter.data = items.filter { it.contains(text) }
adapter.notifyDataSetChanged()
}
}
}
ItemListActivity.kt
class ItemListActivity : Activity() {
companion object {
private val TAG = ItemListActivity::class.java.simpleName
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_item_list)
val toolbar = findViewById<Toolbar>(R.id.toolbar)
toolbar.title = "検索"
setActionBar(toolbar)
if (savedInstanceState == null) {
val itemListFragment = ItemListFragment()
val transaction = fragmentManager.beginTransaction()
transaction.replace(R.id.container, itemListFragment)
transaction.commit()
}
}
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
menuInflater.inflate(R.menu.search, menu)
if (menu != null) {
val searchView = menu.findItem(R.id.menu_search).actionView as SearchView
searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(text: String?): Boolean {
Log.d(TAG, "submit text: $text")
return false
}
override fun onQueryTextChange(text: String?): Boolean {
Log.d(TAG, "change text: $text")
val itemListFragment = fragmentManager.findFragmentById(R.id.container)
if (itemListFragment is ItemListFragment && text != null) {
itemListFragment.searchRequest(text)
}
return false
}
})
}
return super.onCreateOptionsMenu(menu)
}
}