【问题标题】:Filtering ListView with custom (object) adapter使用自定义(对象)适配器过滤 ListView
【发布时间】:2011-08-12 10:11:22
【问题描述】:

我正在尝试对使用自定义对象适配器的 ListView 进行过滤,但我找不到任何有用的示例。包含的代码非常简化,所以请记住,我不能使用常规的 ArrayAdapter。 我在 ListView 上方有一个 EditText,当用户在 EditText 小部件中输入文本时,我想通过 EditText 中写入的文本过滤 ListView。 任何建议将不胜感激!

这是来自活动类的 sn-p:

public class management_objects extends Activity {

private static List<User> UserList;
private EfficientAdapter adapter = null;
private ListView objectListView = null;
private EditText SearchText = null;

private static class EfficientAdapter extends BaseAdapter implements Filterable{
    private LayoutInflater mInflater;   

    public EfficientAdapter(Context context) {
        mInflater = LayoutInflater.from(context);
    }

    public int getCount() {
        return UserList.size();
    }

    public Object getItem(int position) {
        return position;
    }

    public long getItemId(int position) {
        return position;
    }

    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder; 
        if (convertView == null) { 
            convertView = mInflater.inflate(R.layout.imagelayout_2lines, null);
            holder = new ViewHolder();
            holder.text = (TextView) convertView.findViewById(R.id.managementObjectText);
            holder.subtext = (TextView) convertView.findViewById(R.id.managementObjectSubText);
            holder.icon = (ImageView) convertView.findViewById(R.id.managementObjectIcon);
            convertView.setTag(holder);
        }
        else {
            holder = (ViewHolder) convertView.getTag();
        }

        holder.text.setText(UserList.get(position).getFirstName());
        holder.subtext.setText(UserList.get(position).getLastName());
        holder.icon.setImageResource(R.drawable.user);

        return convertView;
    }

    static class ViewHolder { 
        TextView text;
        TextView subtext;
        ImageView icon;
    }

    @Override
    public Filter getFilter() {
        return null;
    }
}

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.adobjectlist);
    Bundle extras = getIntent().getExtras();

    SearchText = (EditText) findViewById(R.id.SearchBox);    
    SearchText.addTextChangedListener(filterTextWatcher);

    objectListView = (ListView) findViewById(R.id.ObjectList);
    objectListView.setOnItemClickListener(Item_Click);
    adapter = new EfficientAdapter(this);
    ComputerName = extras.getString("COMPUTER_NAME");

    //Get User list from webservice
    ShowUsers();
}

这是用户类:

 public class User {
  private int UserId;
  private String FirstName;
  private String LastName;

    public int getUserId() {
        return UserId;
    }
    public void setUserId(int UserId) {
        this.UserId = UserId;
    }
    public String getFirstName() {
        return FirstName;
    }
    public void setFirstName(String FirstName) {
        this.FirstName = FirstName;
    }
    public String getLastName() {
        return LastName;
    }
    public void setLastName(String LastName) {
        this.LastName = LastName;
    }
}

【问题讨论】:

    标签: android listview filter adapter


    【解决方案1】:

    你需要做几件事:

    1) 在您的活动中,在您的 EditText 上注册一个文本更改侦听器,其中包含用户输入的值:

    mSearchValue.addTextChangedListener(searchTextWatcher);

    2) 创建你的 searchTextWatcher 并让它做一些事情:

    private TextWatcher searchTextWatcher = new TextWatcher() {
        @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
                // ignore
            }
    
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
                // ignore
            }
    
            @Override
            public void afterTextChanged(Editable s) {
                Log.d(Constants.TAG, "*** Search value changed: " + s.toString());
                adapter.getFilter().filter(s.toString());
            }
        };
    

    3) 覆盖自定义适配器中的 getFilter() 并让它过滤结果并通知列表视图数据集已更改。

        @Override
        public Filter getFilter() {
            return new Filter() {
                @SuppressWarnings("unchecked")
                @Override
                protected void publishResults(CharSequence constraint, FilterResults results) {
                    Log.d(Constants.TAG, "**** PUBLISHING RESULTS for: " + constraint);
                    myData = (List<MyDataType>) results.values;
                    MyCustomAdapter.this.notifyDataSetChanged();
                }
    
                @Override
                protected FilterResults performFiltering(CharSequence constraint) {
                    Log.d(Constants.TAG, "**** PERFORM FILTERING for: " + constraint);
                    List<MyDataType> filteredResults = getFilteredResults(constraint);
    
                    FilterResults results = new FilterResults();
                    results.values = filteredResults;
    
                    return results;
                }
            };
        }
    

    【讨论】:

    • 为什么在 3) 中说“覆盖”? BaseAdapter 没有 getFilter()。
    • 很好——不需要。我的自定义适配器类(实际上是从 AmazingListView 开源小部件的 AmazingAdapter 继承)实现需要 getFilter() 的 android.widget.Filterable 接口。
    • This tutorial 帮助了我。答案有一些不清楚的地方,或者我没有足够专注地阅读它。
    • @Dustin 这个 getFilteredResults(constraint) 方法是什么?我试过你的答案。但该方法不支持ne。
    • @anuruddhika,这只是您进行所需过滤的方法,并将返回结果。这不是您要覆盖的 Android 方法。
    【解决方案2】:

    这是一个有趣的例子

    public Filter getFilter() {
        return new Filter() {
    
            @Override
            protected FilterResults performFiltering(CharSequence constraint) {
                final FilterResults oReturn = new FilterResults();
                final ArrayList<station> results = new ArrayList<station>();
                if (orig == null)
                    orig = items;
                if (constraint != null) {
                    if (orig != null && orig.size() > 0) {
                        for (final station g : orig) {
                            if (g.getName().toLowerCase()
                                    .contains(constraint.toString()))
                                results.add(g);
                        }
                    }
                    oReturn.values = results;
                }
                return oReturn;
            }
    
            @SuppressWarnings("unchecked")
            @Override
            protected void publishResults(CharSequence constraint,
                    FilterResults results) {
                items = (ArrayList<station>) results.values;
                notifyDataSetChanged();
            }
        };
    }
    
    public void notifyDataSetChanged() {
        super.notifyDataSetChanged();
        notifyChanged = true;
    }
    

    【讨论】:

    • 使用 ORIG 变量保存初始实例的绝佳方法。效果很好,谢谢。
    【解决方案3】:

    对于那些不需要Filterable 接口的人来说,有一个更简单的解决方案。这也可以在其他解决方案失败的情况下正确处理notifyDataSetChanged()。请注意,您需要在 BaseAdapter 中添加一个 getArray() 函数,该函数只返回传递给构造函数的数组对象。

    public abstract class BaseFilterAdapter<T> extends BaseAdapter<T> {
    
        private List<T> original;
        private String lastFilter;
    
        public BaseFilterAdapter(Context context, List<T> array) {
            super(context, new LinkedList<T>());
            original = array;
            filter("");
        }
    
        protected abstract Boolean predicate(T element, String filter);
    
        public void filter(String filter) {
            lastFilter = filter;
            super.getArray().clear();
            for (T element : original)
                if (predicate(element, filter))
                    super.getArray().add(element);
            super.notifyDataSetChanged();
        }
    
        @Override
        public List<T> getArray() {
            return original;
        }
    
        @Override
        public void notifyDataSetChanged() {
            filter(lastFilter);
        }
    }
    

    【讨论】:

    • BaseAdapter 类中没有可覆盖的 getArray 方法。
    【解决方案4】:

    在您的基类上添加 toString 覆盖。例如

    @Override
    public String toString() {
        return this.name;
    }
    

    Above 使您的 List 成为字符串列表。所以你可以使用:

    your_edit_text.addTextChangedListener(new TextWatcher() {
    
        @Override
        public void onTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {
            YourActivity.this.YourAdapter.getFilter().filter(arg0);
        }
    
        @Override
        public void beforeTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {
        }
    
        @Override
        public void afterTextChanged(Editable arg0) {    
        }
    });
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-12-06
      • 2018-11-29
      • 1970-01-01
      • 2014-09-06
      • 1970-01-01
      相关资源
      最近更新 更多