You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android带搜索下拉菜单问题:限制选择与模糊搜索实现

用AutocompleteTextView实现限制输入+包含式搜索

完全可以通过自定义适配器和添加监听来实现你需要的两个功能,下面是具体方案:

一、实现包含式搜索(解决需求b)

默认的ArrayAdapter采用前缀匹配,我们需要自定义适配器并重写Filter来实现包含式过滤:

class ContainsFilterArrayAdapter(context: Context, resource: Int, objects: List<String>) :
    ArrayAdapter<String>(context, resource, objects) {

    private val originalList = ArrayList(objects)

    override fun getFilter(): Filter {
        return object : Filter() {
            override fun performFiltering(constraint: CharSequence?): FilterResults {
                val results = FilterResults()
                val filteredList = ArrayList<String>()

                constraint?.let { query ->
                    val lowerCaseQuery = query.toString().lowercase()
                    originalList.forEach { item ->
                        // 忽略大小写的包含匹配
                        if (item.lowercase().contains(lowerCaseQuery)) {
                            filteredList.add(item)
                        }
                    }
                } ?: run {
                    filteredList.addAll(originalList)
                }

                results.values = filteredList
                results.count = filteredList.size
                return results
            }

            override fun publishResults(constraint: CharSequence?, results: FilterResults?) {
                clear()
                results?.values?.let { values ->
                    addAll(values as Collection<String>)
                }
                notifyDataSetChanged()
            }
        }
    }
}

二、禁止自定义输入(解决需求a)

不能用android:inputType="none"(会丢失搜索功能),而是通过监听输入和焦点变化,确保最终只有预定义选项能保留:

在Fragment中设置适配器并添加监听:

val countries = arrayListOf("Czech Republic","Slovakia", "Poland", "Germany","Austria")
val countriesAdapter = ContainsFilterArrayAdapter(requireContext(), R.layout.support_simple_spinner_dropdown_item, countries)
binding?.actCountries?.apply {
    setAdapter(countriesAdapter)
    // 记录用户选中的有效选项
    var selectedCountry: String? = null

    // 选中项时保存当前值
    onItemClickListener = AdapterView.OnItemClickListener { _, _, position, _ ->
        selectedCountry = countriesAdapter.getItem(position)
    }

    // 失去焦点时验证文本有效性,无效则重置
    onFocusChangeListener = View.OnFocusChangeListener { _, hasFocus ->
        if (!hasFocus) {
            val currentText = text.toString()
            if (currentText.isNotEmpty() && !countries.contains(currentText)) {
                // 重置为上次选中的内容,也可以直接清空
                setText(selectedCountry ?: "", false)
            }
        }
    }

    // 软键盘完成键触发时验证
    setOnEditorActionListener { _, actionId, _ ->
        if (actionId == EditorInfo.IME_ACTION_DONE) {
            val currentText = text.toString()
            if (currentText.isNotEmpty() && !countries.contains(currentText)) {
                setText(selectedCountry ?: "", false)
                // 隐藏软键盘
                val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
                imm.hideSoftInputFromWindow(windowToken, 0)
            }
            true
        } else {
            false
        }
    }
}

三、XML布局保持不变

你的原有布局无需修改,继续使用TextInputLayout搭配AutocompleteTextView即可:

<com.google.android.material.textfield.TextInputLayout
    style="@style/Widget.Material3.TextInputLayout.OutlinedBox.ExposedDropdownMenu"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:hint="Country">

    <AutoCompleteTextView
        android:id="@+id/actCountries"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
    </AutoCompleteTextView>
</com.google.android.material.textfield.TextInputLayout>

效果说明

  • 用户可以输入内容进行搜索,输入的字符会在所有预定义选项中进行包含式匹配(比如输入"land"会匹配到"Poland")
  • 输入的内容如果不在预定义列表中,失去焦点或按下完成键时会自动重置为上次选中的内容(或清空),确保最终只能选择预定义选项

内容的提问来源于stack exchange,提问作者OndraVojta

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 13:53:14