自定义 ArrayAdapter 上的 getFilter() 不起作用
getFilter() on a custom ArrayAdapter not working
我正在使用 Custom ArrayAdapter 来存储用户信息,例如 sammy、robert、lizie 都是用户对象,我正在使用用户类型 ArrayList 将所有用户对象存储到 ArrayList。
并且因为它不是字符串或整数(ArrayList),所以默认的 getFilter 不起作用,我已经完成了研究,但确实令人困惑 getFilter 方法有效,所以我可以修改自己。
我想实现基于name
属性形式的搜索User class
我知道我必须在我的 CustomAdapter class 中实现 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;
}
}
这里是用户 class 这里没什么特别的
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 的很多变体,但其中 none 对我有用,并且有很好解释的是 BaseAdapter 而不是 ArrayAdapter
我试过这个 question and i have tried this question 但对我不起作用。
我是 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;
}
}
自定义适配器上的搜索不工作我仍然认为我做错了什么。
我在搜索栏中输入内容,但没有过滤
如果您想查看搜索条码,它没什么特别的,只是通常的
@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();
}
}
};
最后,覆盖此方法和 return 过滤器实例。
@Override
public Filter getFilter() {
return myFilter;
}
ArrayAdapter
的 built-in Filter
使用模型 class 中的 toString()
return(即它的类型参数)来执行其过滤比较。如果您能够将 User
的 toString()
方法覆盖到 return 您想要比较的内容(提供其过滤算法),则不一定需要自定义 Filter
实现适合你的情况)。在这种情况下:
@Override
public String toString() {
return name;
}
为了明确该算法的确切含义,ArrayAdapter
的默认过滤如下:
过滤器String
首先转换为小写。然后,遍历数据集,将每个值的 toString()
return 转换为小写,并检查它是否 startsWith()
过滤器 String
。如果是,则将其添加到结果集中。如果不是,则执行第二次检查,其中值的小写 String
在 space (" "
) 上拆分,并将来自该值的每个值与过滤器进行比较,再次使用 startsWith()
。基本上,它首先检查整个内容是否以过滤文本开头,然后在必要时检查每个单词。
如果这是一个合适的过滤器,那么这个解决方案是迄今为止最简单的。
如果这不能满足您的需求,并且您确实需要自定义 Filter
实现,那么您不应该一开始就使用 ArrayAdapter
。 ArrayAdapter
维护内部,private List
s 用于原始和过滤后的 collections – 最初从构造函数调用中传递的 collection 填充 – 你无权访问这些。这就是显示的自定义 Filter
尝试不起作用的原因,因为显示的项目计数和从 getItem(position)
编辑的项目 return 来自内部过滤器 List
,而不是一个内置于自定义 Filter
.
在这种情况下,您应该直接子class BaseAdapter
,维护您自己的 List
用于原始和过滤后的 collection。您可以使用 ArrayAdapter
's source 作为指南。
确实,在选择 Adapter
进行扩展时,ArrayAdapter
通常是错误的选择。 ArrayAdapter
是为一个单一的、有些简单的目标而设计的:在每个列表项中的单个 TextView
上设置一个平面 String
。在某些情况下,subclassing ArrayAdapter
而不是 BaseAdapter
是毫无意义的 and/or 多余的。例如:
- 覆盖
getView()
并且不使用 View
return 调用 super.getView()
.
- 出于某种原因手动设置
TextView
上的文本。
- 维护和使用您自己的 collection;即,数组,或
List
s,或者你有什么。
在这些和某些其他情况下,可以说从一开始就使用 BaseAdapter
更好。将 ArrayAdapter
用于比具有基本功能的单个文本项复杂得多的任何东西很快就会变得麻烦 error-prone,而且往往比它的价值更麻烦。
最后,我要提到的是 ListView
在撰写本文时基本上已被弃用,尽管尚未正式弃用。目前的建议是改用 RecyclerView
。但是,对于 Android 编程的新手,ListView
仍然可以作为了解此类回收适配器 View
总体设计的第一步。 RecyclerView
一开始可能有点不知所措。
我正在使用 Custom ArrayAdapter 来存储用户信息,例如 sammy、robert、lizie 都是用户对象,我正在使用用户类型 ArrayList 将所有用户对象存储到 ArrayList。
并且因为它不是字符串或整数(ArrayList),所以默认的 getFilter 不起作用,我已经完成了研究,但确实令人困惑 getFilter 方法有效,所以我可以修改自己。
我想实现基于name
属性形式的搜索User class
我知道我必须在我的 CustomAdapter class 中实现 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;
}
}
这里是用户 class 这里没什么特别的
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 的很多变体,但其中 none 对我有用,并且有很好解释的是 BaseAdapter 而不是 ArrayAdapter
我试过这个 question and i have tried this question 但对我不起作用。
我是 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;
}
}
自定义适配器上的搜索不工作我仍然认为我做错了什么。
我在搜索栏中输入内容,但没有过滤
如果您想查看搜索条码,它没什么特别的,只是通常的
@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();
}
}
};
最后,覆盖此方法和 return 过滤器实例。
@Override
public Filter getFilter() {
return myFilter;
}
ArrayAdapter
的 built-in Filter
使用模型 class 中的 toString()
return(即它的类型参数)来执行其过滤比较。如果您能够将 User
的 toString()
方法覆盖到 return 您想要比较的内容(提供其过滤算法),则不一定需要自定义 Filter
实现适合你的情况)。在这种情况下:
@Override
public String toString() {
return name;
}
为了明确该算法的确切含义,ArrayAdapter
的默认过滤如下:
过滤器String
首先转换为小写。然后,遍历数据集,将每个值的 toString()
return 转换为小写,并检查它是否 startsWith()
过滤器 String
。如果是,则将其添加到结果集中。如果不是,则执行第二次检查,其中值的小写 String
在 space (" "
) 上拆分,并将来自该值的每个值与过滤器进行比较,再次使用 startsWith()
。基本上,它首先检查整个内容是否以过滤文本开头,然后在必要时检查每个单词。
如果这是一个合适的过滤器,那么这个解决方案是迄今为止最简单的。
如果这不能满足您的需求,并且您确实需要自定义 Filter
实现,那么您不应该一开始就使用 ArrayAdapter
。 ArrayAdapter
维护内部,private List
s 用于原始和过滤后的 collections – 最初从构造函数调用中传递的 collection 填充 – 你无权访问这些。这就是显示的自定义 Filter
尝试不起作用的原因,因为显示的项目计数和从 getItem(position)
编辑的项目 return 来自内部过滤器 List
,而不是一个内置于自定义 Filter
.
在这种情况下,您应该直接子class BaseAdapter
,维护您自己的 List
用于原始和过滤后的 collection。您可以使用 ArrayAdapter
's source 作为指南。
确实,在选择 Adapter
进行扩展时,ArrayAdapter
通常是错误的选择。 ArrayAdapter
是为一个单一的、有些简单的目标而设计的:在每个列表项中的单个 TextView
上设置一个平面 String
。在某些情况下,subclassing ArrayAdapter
而不是 BaseAdapter
是毫无意义的 and/or 多余的。例如:
- 覆盖
getView()
并且不使用View
return 调用super.getView()
. - 出于某种原因手动设置
TextView
上的文本。 - 维护和使用您自己的 collection;即,数组,或
List
s,或者你有什么。
在这些和某些其他情况下,可以说从一开始就使用 BaseAdapter
更好。将 ArrayAdapter
用于比具有基本功能的单个文本项复杂得多的任何东西很快就会变得麻烦 error-prone,而且往往比它的价值更麻烦。
最后,我要提到的是 ListView
在撰写本文时基本上已被弃用,尽管尚未正式弃用。目前的建议是改用 RecyclerView
。但是,对于 Android 编程的新手,ListView
仍然可以作为了解此类回收适配器 View
总体设计的第一步。 RecyclerView
一开始可能有点不知所措。