[英]getFilter() on a custom ArrayAdapter not working
我正在使用自定义 ArrayAdapter来存储用户信息,例如 sammy、robert、lizie 都是一个 User 对象,我正在使用 User 类型ArrayList将所有 User 对象存储到ArrayList 。
并且因为它不是字符串或整数(ArrayList),所以默认的getFilter不起作用,我已经完成了我的研究,但是getFilter方法的工作方式确实令人困惑,因此我可以修改自己。
我想根据User class
的name
属性实现搜索
我知道我必须在我的CustomAdapter类中实现Filterable接口,但getFilter真的不直观。
这是我的 CustomAdapter
class CustomArrayAdapter extends ArrayAdapter<User> implements Filterable {
CustomArrayAdapter(@NonNull Context context, ArrayList<User> users) {
super(context, 0, users);
}
@NonNull
@Override
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
User innserUser = getItem(position);
if (convertView == null){
convertView = LayoutInflater.from(getContext()).inflate(R.layout.row_layout, parent, false);
}
TextView username = (TextView) convertView.findViewById(R.id.userNameContact);
TextView userNumber = (TextView) convertView.findViewById(R.id.userNumberContact);
ImageView userImage = (ImageView) convertView.findViewById(R.id.userImageContact);
try {
if(innserUser != null) {
username.setText(innserUser.name);
userNumber.setText(innserUser.number);
userImage.setImageBitmap(innserUser.imageBitmap);
}
}catch (Exception e){
e.printStackTrace();
}
return convertView;
}
}
这是用户类,这里没什么特别的
import android.graphics.Bitmap;
public class User {
String id, name, number;
Bitmap imageBitmap;
User(String id, String name, String number, Bitmap imageBitmap){
this.id = id;
this.name = name;
this.number = number;
this.imageBitmap = imageBitmap;
}
}
我从许多线程中绑定了很多getFilter的变体,但没有一个对我有用,有很好解释的是 BaseAdapter 而不是 ArrayAdapter
我是 android 开发领域的新手,这似乎特别不直观。 任何建议将不胜感激,谢谢。
编辑 1 :在jitesh mohite的回答之后,感谢jitesh mohite的重播
class CustomArrayAdapter extends ArrayAdapter<User> implements Filterable {
ArrayList<User> users;
CustomArrayAdapter(@NonNull Context context, ArrayList<User> users) {
super(context, 0, users);
this.users = users;
}
@NonNull
@Override
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
User innserUser = getItem(position);
if (convertView == null){
convertView = LayoutInflater.from(getContext()).inflate(R.layout.row_layout, parent, false);
}
TextView username = (TextView) convertView.findViewById(R.id.userNameContact);
TextView userNumber = (TextView) convertView.findViewById(R.id.userNumberContact);
ImageView userImage = (ImageView) convertView.findViewById(R.id.userImageContact);
try {
if(innserUser != null) {
username.setText(innserUser.name);
userNumber.setText(innserUser.number);
userImage.setImageBitmap(innserUser.imageBitmap);
}
}catch (Exception e){
e.printStackTrace();
}
return convertView;
}
Filter myFilter = new Filter() {
@Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults filterResults = new FilterResults();
ArrayList<User> tempList=new ArrayList<User>();
// Add the filter code here
if(constraint != null && users != null) {
int length= users.size();
int i=0;
while(i<length){
User item= users.get(i);
//do whatever you wanna do here
//adding result set output array
//item.name is user.name cause i want to search on name
if(item.name.toLowerCase().contains(constraint.toString().toLowerCase()) ) { // Add check here, and fill the tempList which shows as a result
tempList.add(item);
}
i++;
}
//following two lines is very important
//as publish result can only take FilterResults users
filterResults.values = tempList;
filterResults.count = tempList.size();
}
return filterResults;
}
@SuppressWarnings("unchecked")
@Override
protected void publishResults(CharSequence contraint, FilterResults results) {
users = (ArrayList<User>) results.values;
if (results.count > 0) {
notifyDataSetChanged();
} else {
notifyDataSetInvalidated();
}
}
};
@Override
public Filter getFilter() {
return myFilter;
}
}
搜索在 customadapter 上不起作用,我仍然认为我做错了什么。
在这里,我在搜索栏中输入了一些内容,但没有进行过滤
如果您想查看搜索栏代码,它没有什么特别的,只是通常的
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.search_box, menu);
MenuItem item = menu.findItem(R.id.app_bar_search);
SearchView searchView = (SearchView)item.getActionView();
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
return false;
}
@Override
public boolean onQueryTextChange(String newText) {
customArrayAdapter.getFilter().filter(newText);
return false;
}
});
return true;
}
Filter myFilter = new Filter() {
@Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults filterResults = new FilterResults();
ArrayList<User> tempList=new ArrayList<User>();
// Add the filter code here
if(constraint != null && users!=null) {
int length= users.size();
int i=0;
while(i<length){
User item= users.get(i);
//do whatever you wanna do here
//adding result set output array
if() { // Add check here, and fill the tempList which shows as a result
tempList.add(item);
}
i++;
}
//following two lines is very important
//as publish result can only take FilterResults users
filterResults.values = tempList;
filterResults.count = tempList.size();
}
return filterResults;
}
@SuppressWarnings("unchecked")
@Override
protected void publishResults(CharSequence contraint, FilterResults results) {
users = (ArrayList<User>) results.values;
if (results.count > 0) {
notifyDataSetChanged();
} else {
notifyDataSetInvalidated();
}
}
};
最后,覆盖此方法并返回过滤器实例。
@Override
public Filter getFilter() {
return myFilter;
}
ArrayAdapter
的内置Filter
使用从模型类(即它的类型参数)返回的toString()
) 来执行其过滤比较。 如果您能够覆盖User
的toString()
方法以返回您想要比较的内容(前提是其过滤算法适合您的情况),则您不一定需要自定义Filter
实现。 在这种情况下:
@Override
public String toString() {
return name;
}
要明确该算法是什么, ArrayAdapter
的默认过滤如下:
过滤器String
首先转换为小写。 然后,循环遍历数据集,将每个值的toString()
返回值转换为小写字母,并检查它是否通过startsWith()
过滤器String
。 如果是,则将其添加到结果集中。 如果不是,则执行第二次检查,从而将值的小写String
拆分为一个空格( " "
),并将其中的每个值与过滤器进行比较,再次使用startsWith()
。 基本上,它首先检查整个事情是否以过滤器文本开头,然后在必要时检查每个单词。
如果这是一个合适的过滤器,那么这个解决方案是迄今为止最简单的。
如果这不能满足您的需求,并且您确实需要自定义Filter
实现,那么您不应该一开始就使用ArrayAdapter
。 ArrayAdapter
为原始和过滤的集合维护内部的private List
ArrayAdapter
最初是从构造函数调用中传递的集合填充的——你无权访问这些。 这就是显示的自定义Filter
尝试不起作用的原因,因为显示的项目计数和从getItem(position)
返回的项目来自该内部过滤器List
,而不是自定义Filter
内置的Filter
。
在这种情况下,您应该直接BaseAdapter
,为原始和过滤的集合维护自己的List
。 您可以使用ArrayAdapter
的源代码作为指南。
实际上,在选择要扩展的Adapter
时, ArrayAdapter
通常是错误的选择。 ArrayAdapter
是为一个单一的、有点简单的目标而设计的:在每个列表项的单个TextView
上设置一个扁平的String
。 在某些情况下, BaseAdapter
ArrayAdapter
而不是BaseAdapter
是毫无意义和/或多余的。 例如:
getView()
并且不使用从调用super.getView()
返回的View
。TextView
上的文本。List
s,或者你有什么。 在这些和某些其他情况下,可以说最好从一开始就使用BaseAdapter
。 将ArrayAdapter
用于比具有基本功能的单个文本项更复杂的任何内容可能会很快变得麻烦且容易出错,并且通常比它的价值更麻烦。
最后,我要提到ListView
基本上已被弃用,尽管在撰写本文时尚未正式发布。 目前的建议是改用RecyclerView
。 然而,对于那些刚开始接触 Android 编程的人来说, ListView
仍然可以作为理解这种类型的回收适配器View
整体设计的开始。 RecyclerView
一开始可能有点让人不知所措。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.