如何使用SearchView按字符而非精确词语过滤ListView?
嘿,这个需求其实很好实现,核心就是给你的ListView做一个支持模糊匹配、不区分大小写的自定义过滤器就行,我给你一步步讲清楚怎么做:
核心思路
默认的适配器过滤器一般是精确匹配或者前缀匹配,咱们要自己写一个过滤器,遍历原始数据,判断每个条目是否包含输入的关键词(同时忽略大小写),把符合条件的结果返回给ListView。
完整代码实现
1. 自定义适配器(带模糊过滤器)
咱们基于ArrayAdapter扩展一个带自定义过滤逻辑的适配器,这样最省心:
import android.content.Context; import android.widget.ArrayAdapter; import android.widget.Filter; import java.util.ArrayList; import java.util.List; public class FuzzySearchAdapter extends ArrayAdapter<String> { // 保存原始完整数据,避免过滤时丢失 private final List<String> originalData; // 保存过滤后的结果数据 private List<String> filteredData; public FuzzySearchAdapter(Context context, List<String> data) { super(context, android.R.layout.simple_list_item_1, data); this.originalData = new ArrayList<>(data); this.filteredData = new ArrayList<>(data); } // 重写getFilter,返回咱们自定义的过滤器 @Override public Filter getFilter() { return new Filter() { // 这个方法在后台线程执行,不要操作UI @Override protected FilterResults performFiltering(CharSequence constraint) { FilterResults results = new FilterResults(); List<String> tempResults = new ArrayList<>(); // 如果没有输入关键词,直接返回全部数据 if (constraint == null || constraint.length() == 0) { tempResults.addAll(originalData); } else { // 把关键词转成小写,统一匹配规则 String searchQuery = constraint.toString().toLowerCase().trim(); // 遍历原始数据,检查每个条目是否包含关键词(同样转小写) for (String item : originalData) { if (item.toLowerCase().contains(searchQuery)) { tempResults.add(item); } } } results.values = tempResults; results.count = tempResults.size(); return results; } // 这个方法在主线程执行,更新UI数据 @Override protected void publishResults(CharSequence constraint, FilterResults results) { filteredData.clear(); filteredData.addAll((List<String>) results.values); // 通知ListView数据更新 notifyDataSetChanged(); } }; } }
2. 在Activity中关联SearchView和ListView
接下来在你的Activity里初始化数据、View和适配器,再给SearchView设置监听:
import android.os.Bundle; import android.widget.ListView; import android.widget.SearchView; import androidx.appcompat.app.AppCompatActivity; import java.util.ArrayList; import java.util.List; public class SearchActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_search); // 1. 初始化你的数据源 List<String> nameList = new ArrayList<>(); nameList.add("mitesh"); nameList.add("vidhi"); nameList.add("ravi"); nameList.add("Ravi P"); nameList.add("Tushar prajapati"); // 2. 绑定View SearchView searchView = findViewById(R.id.search_view); ListView listView = findViewById(R.id.list_view); // 3. 设置自定义适配器 FuzzySearchAdapter adapter = new FuzzySearchAdapter(this, nameList); listView.setAdapter(adapter); // 4. 给SearchView设置查询监听,实时过滤 searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() { @Override public boolean onQueryTextSubmit(String query) { // 提交搜索时触发 adapter.getFilter().filter(query); return false; } @Override public boolean onQueryTextChange(String newText) { // 输入内容变化时实时过滤 adapter.getFilter().filter(newText); return false; } }); // 可选:设置SearchView的提示文字 searchView.setQueryHint("输入关键词搜索..."); } }
额外说明
- 如果你的ListView展示的是自定义对象(不是String),只需要修改
performFiltering里的判断逻辑就行,比如:if (user.getName().toLowerCase().contains(searchQuery)) - 为什么要保存
originalData?因为每次过滤都需要从原始完整数据里筛选,避免过滤后的数据被二次过滤导致数据丢失 - 性能方面:如果你的数据集特别大(比如几千条以上),可以考虑用更高效的匹配算法,或者用异步任务优化,但一般中小数据集这个方案完全够用
内容的提问来源于stack exchange,提问作者Rk215 Tech
相关产品推荐
相关产品推荐

