繁体   English   中英

自定义 ArrayAdapter 上的 getFilter() 不起作用

[英]getFilter() on a custom ArrayAdapter not working

我正在使用自定义 ArrayAdapter来存储用户信息,例如 sammy、robert、lizie 都是一个 User 对象,我正在使用 User 类型ArrayList将所有 User 对象存储到ArrayList

并且因为它不是字符串或整数(ArrayList),所以默认的getFilter不起作用,我已经完成了我的研究,但是getFilter方法的工作方式确实令人困惑,因此我可以修改自己。

我想根据User classname属性实现搜索

我知道我必须在我的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;
    }

如需更多参考,请参阅https://gist.github.com/tobiasschuerg/3554252

ArrayAdapter的内置Filter使用从模型类(即它的类型参数)返回的toString() ) 来执行其过滤比较。 如果您能够覆盖UsertoString()方法以返回您想要比较的内容(前提是其过滤算法适合您的情况),则您不一定需要自定义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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM