如何对SearchView实施缩写搜索

时间:2019-03-24 15:07:47

标签: android kotlin searchview android-search android-searchmanager

我有一个Fragment,其中包含与SearchView一起使用的字符串(公司名称)列表。但是,由于许多公司都使用长名称,是否有一种方法可以键入公司名称的缩写,而不必键入整个公司名称? “ FTSE 150”和“ FTSE 250”是不言自明的,因此不需要缩写。

公司名称缩写

  • GSK-GlaxoSmithKline plc
  • HSX-Hiscox Ltd
  • 洲际酒店集团-洲际 酒店集团plc
  • MKS-Marks&Spencer Group plc

strings.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string-array name="company_names">
        <item>@string/glaxosmithkline_plc</item>
        <item>@string/hiscox_ltd</item>
        <item>@string/intercontinental_hotels_group_plc</item>
        <item>@string/marks_and_spencer_group_plc</item>
        <item>@string/ftse_150</item>
        <item>@string/ftse_250</item>
    </string-array>

    <string name="glaxosmithkline_plc">GlaxoSmithKline plc</string>
    <string name="hiscox_ltd">Hiscox Ltd</string>
    <string name="intercontinental_hotels_group_plc">InterContinental Hotels Group plc</string>
    <string name="marks_and_spencer_group_plc">Marks &amp; Spencer Group plc</string>
    <string name="ftse_150">FTSE 150</string>
    <string name="ftse_250">FTSE 250</string>
</resources>

片段类

class MyFragment : androidx.fragment.app.Fragment() {

    private var mAdapter: MyListAdapter? = null

    private lateinit var mRecyclerView: androidx.recyclerview.widget.RecyclerView

    private var mTwoPane: Boolean = false

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setHasOptionsMenu(true)
    }

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        val view = inflater.inflate(R.layout.layout_recyclerview, container, false)
        mTwoPane = (activity as androidx.fragment.app.FragmentActivity).findViewById<View>(R.id.detail_container) != null

        mRecyclerView = view.findViewById(R.id.recyclerView_list)
        mRecyclerView.setHasFixedSize(true)
        mRecyclerView.layoutManager = androidx.recyclerview.widget.LinearLayoutManager(this.activity)
        mRecyclerView.addItemDecoration(androidx.recyclerview.widget.DividerItemDecoration(Objects.requireNonNull<Context>(context), LinearLayout.VERTICAL))

        val myList = ArrayList<Companies>()

//        val items = resources.getStringArray(R.array.company_names)
//        for (n in items) {
//            val company = Companies(0, "", "")
//            myList.add(company)
//        }

        val companyA = Companies(1, "GlaxoSmithKline plc", "GSK")
        val companyB = Companies(2, "Hiscox Ltd", "HSX")
        val companyC = Companies(3, "InterContinental Hotels Group plc", "IHG")
        val companyD = Companies(4, "Marks & Spencer Group plc", "MKS")
        val companyE = Companies(5, "FTSE 150", "")
        val companyF = Companies(6, "FTSE 250", "")

        val myList = DatabaseHandler(this.context!!)
        myList.insertData(companyA)
        myList.insertData(companyB)
        myList.insertData(companyC)
        myList.insertData(companyD)
        myList.insertData(companyE)
        myList.insertData(companyF)

        mAdapter = MyListAdapter(activity!!, myList, mTwoPane)

        mRecyclerView.adapter = mAdapter

        return view
    }

    override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
        val mInflater = Objects.requireNonNull<androidx.fragment.app.FragmentActivity>(activity).menuInflater
        mInflater.inflate(R.menu.menu_search, menu)

        val searchView = searchitem.actionView as SearchView

        searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
            override fun onQueryTextSubmit(query: String): Boolean {
                return false
            }

            override fun onQueryTextChange(newText: String): Boolean {
                mAdapter!!.filter.filter(newText)
                return false
            }
        })

        super.onCreateOptionsMenu(menu, inflater)
    }
}

MyListAdapter类

class MyListAdapter(private val mCtx: Context, private val myList: MutableList<Companies>,
                          private val
mTwoPane: Boolean) : androidx.recyclerview.widget.RecyclerView.Adapter<MyListAdapter
.CompanyViewHolder>(), Filterable {
    private var myListFull = myList.toMutableList()

    private val companyFilter = object : Filter() {
        override fun performFiltering(constraint: CharSequence?): Filter.FilterResults {
            val filteredList = ArrayList<Companies>()

            when {
                constraint == null || constraint.isEmpty() -> filteredList.addAll(myListFull)
                else -> {
                    val filterPattern = constraint.toString().toLowerCase().trim { it <= ' ' }

                    for (item in myListFull) {
                        when {
                            item.companyName!!.toLowerCase().contains(filterPattern) ->
                                filteredList.add(item)
                        }
                    }
                }
            }

            val results = Filter.FilterResults()
            results.values = filteredList
            return results
        }

        override fun publishResults(constraint: CharSequence?, results: Filter.FilterResults?) {
            myList.clear()
            myList.addAll(results!!.values as List<Companies>)
            notifyDataSetChanged()
        }
    }

    inner class CompanyViewHolder(itemView: View) : androidx.recyclerview.widget.RecyclerView
    .ViewHolder(itemView) {
        var tvTitle: TextView = itemView.findViewById(R.id.tv_RVItem)
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CompanyViewHolder {
        val inflater = LayoutInflater.from(mCtx)
        val v = inflater.inflate(R.layout.recyclerview_item_textview, parent, false)
        return CompanyViewHolder(v)
    }

    override fun onBindViewHolder(holder: CompanyViewHolder, position: Int) {
        val product = myList[holder.adapterPosition]

        holder.tvTitle.text = product.companyfuName
    }

    override fun getItemCount(): Int {
        return myList.size
    }

    override fun getFilter(): Filter {
        return companyFilter
    }
}

enter image description here

enter image description here

enter image description here

更新

自定义模型类

data class Companies (val id: String, val fullName: String, val abbreviation: String)

更新了适配器类

class MyListAdapter(private val mCtx: Context,
                    private val mCompanies: MutableList<Companies>,
                    private val mTwoPane: Boolean) : androidx.recyclerview.widget.RecyclerView.Adapter<MyListAdapter
.CompanyViewHolder>(), Filterable {
    private val mCompaniesFull = mCompanies.toMutableList()

    private val companyFilter = object : Filter() {
        override fun performFiltering(constraint: CharSequence?): Filter.FilterResults {
            val filteredList = if (constraint == null || constraint.isEmpty()) {
                mCompanies
            } else {
                val filterText = constraint.toString()
                mCompanies.filter { it.companyName.matchesIgnoreCase(filterText) || it.companyAbbreviation.matchesIgnoreCase(filterText) }
            }

            val results = Filter.FilterResults()
            results.values = filteredList
            return results
        }

        override fun publishResults(constraint: CharSequence?, results: Filter.FilterResults?) {
            mCompanies.clear()
            mCompanies.addAll(results!!.values as List<Companies>)
            notifyDataSetChanged()
        }
    }

    private fun String.matchesIgnoreCase(otherString: String): Boolean {
        return this.toLowerCase().contains(otherString.trim().toLowerCase())
    }

    inner class CompanyViewHolder(itemView: View) : androidx.recyclerview.widget.RecyclerView
    .ViewHolder(itemView) {
        var tvTitle: TextView = itemView.findViewById(R.id.tv_RVItem)
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CompanyViewHolder {
        val inflater = LayoutInflater.from(mCtx)
        val v = inflater.inflate(R.layout.recyclerview_item_textview, parent, false)
        return CompanyViewHolder(v)
    }

    override fun onBindViewHolder(holder: CompanyViewHolder, position: Int) {
        val product = mCompanies[holder.adapterPosition]
        holder.tvTitle.text = product.companyName
    }

    override fun getItemCount(): Int {
        return mCompanies.size
    }

    override fun getFilter(): Filter {
        return companyFilter
    }
}

更新的片段类

class MonFragment : androidx.fragment.app.Fragment() {

    private var mAdapter: MyListAdapter? = null

    private lateinit var mRecyclerView: androidx.recyclerview.widget.RecyclerView

    private var mTwoPane: Boolean = false

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setHasOptionsMenu(true)
    }

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        val view = inflater.inflate(R.layout.layout_recyclerview, container, false)
        mTwoPane = (activity as androidx.fragment.app.FragmentActivity).findViewById<View>(R.id.detail_container) != null

        mRecyclerView = view.findViewById<RecyclerView>(R.id.recyclerView_list)
        mRecyclerView.setHasFixedSize(true)
        mRecyclerView.layoutManager = androidx.recyclerview.widget.LinearLayoutManager(this.activity)
        mRecyclerView.addItemDecoration(androidx.recyclerview.widget.DividerItemDecoration(Objects.requireNonNull<Context>(context), LinearLayout.VERTICAL))

        mCompanies.add(Companies("GlaxoSmithKline plc", "GSK"))
        mCompanies.add(Companies("Hiscox Ltd", "HSX"))
        mCompanies.add(Companies("InterContinental Hotels Group plc", "IHG"))
        mCompanies.add(Companies("Marks & Spencer Group plc", "MKS"))
        mCompanies.add(Companies("FTSE 150", ""))
        mCompanies.add(Companies("FTSE 250", ""))

        mAdapter = MyListAdapter(activity!!, mCompanies, mTwoPane)

        mRecyclerView.adapter = mAdapter

        return view
    }

    override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
        val mInflater = Objects.requireNonNull<androidx.fragment.app.FragmentActivity>(activity).menuInflater
        mInflater.inflate(R.menu.menu_search, menu)

        val searchitem = menu.findItem(R.id.action_search)
        val searchView = searchitem.actionView as SearchView

        searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
            override fun onQueryTextSubmit(query: String): Boolean {
                return false
            }

            override fun onQueryTextChange(newText: String): Boolean {
                mAdapter!!.filter.filter(newText)
                mAdapter!!.notifyDataSetChanged()

                return false
            }
        })

        super.onCreateOptionsMenu(menu, inflater)
    }
}

1 个答案:

答案 0 :(得分:1)

在评论中进行讨论之后,我将建议两种存储数据的方法:

  1. 使用SharedPreferences或数据库SQLiteRoom进行设备存储(它们是轻量级本地存储数据库,不需要Internet连接)。
  2. 设备内存(不推荐使用 )作为通过Map<String,String>MainActivity的{​​{1}}方法初始化的硬编码对象的列表(取决于用法) 。

按照@CoolMind的建议,您应该实现自定义模型类Fragment,然后通过onCreateCompanyName(id, fullName, abbreviation)的替代项进行过滤。

编辑:fullName中删除abbreviation,因为它什么都不做,然后放上:

MyListAdapter

还要在myListFull类中添加此扩展功能:

private val stockFilter = object : Filter() {
        override fun performFiltering(constraint: CharSequence?): Filter.FilterResults {
            val filteredList = if (constraint == null || constraint.isEmpty()) myList
                else {
                   val filterText = constraint.toString()
                   myList.filter { it.fullName.matchesIgnoreCase(filterText ) || it.abbreviation.matchesIgnoreCase(filterText) }
                }
            val results = Filter.FilterResults()
            results.values = filteredList
            return results
        }
}