Searchview用于部分单词搜索

时间:2015-06-25 18:06:53

标签: android searchview

我想在Android中实现SearchView部分字词搜索。 我已经建立了以下搜索机制,如何获得部分单词搜索功能?

EG。如果我搜索" stackover ..",则会出现stackoverflow但是如果我搜索" tackover .." stackoverflow没有出现,我需要它来搜索单词中的部分匹配。

package jagranerp.myapplication;

import java.util.ArrayList;
import java.util.HashMap;

import android.app.Activity;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.ListView;

public class MainActivity extends Activity {

    // List view
    private ListView lv;

    // Listview Adapter
    ArrayAdapter<String> adapter;

    // Search EditText
    EditText inputSearch;


    // ArrayList for Listview
    ArrayList<HashMap<String, String>> productList;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Listview Data
        String products[] = {"Dell Inspiron", "HTC One X", "HTC Wildfire S", "HTC Sense", "HTC Sensation XE",
                "iPhone 4S", "Samsung Galaxy Note 800",
                "Samsung Galaxy S3", "MacBook Air", "Mac Mini", "MacBook Pro"};

        lv = (ListView) findViewById(R.id.list_view);
        inputSearch = (EditText) findViewById(R.id.inputSearch);

        // Adding items to listview
        adapter = new ArrayAdapter<String>(this, R.layout.list_item, R.id.product_name, products);
        lv.setAdapter(adapter);

        /**
         * Enabling Search Filter
         * */
        inputSearch.addTextChangedListener(new TextWatcher() {

            @Override
            public void onTextChanged(CharSequence cs, int arg1, int arg2, int arg3) {
                // When user changed the Text
                MainActivity.this.adapter.getFilter().filter(cs);
            }

            @Override
            public void beforeTextChanged(CharSequence arg0, int arg1, int arg2,
                                          int arg3) {
                // TODO Auto-generated method stub

            }

            @Override
            public void afterTextChanged(Editable arg0) {
                // TODO Auto-generated method stub
            }
        });
    }

}

2 个答案:

答案 0 :(得分:0)

The filter() method will return the coincidences of the keyword "cs". In this example, "Stackoverflow" will not match "tackover" because the comparison will evaulate if "Stackoverflow" starts with "Tackover". As it will return false, then its not going to make it through the filter.

I'm not quite sure of how a filter works but you could use the method contains(String arg) of a String class. This method will return true if any match is found of the given argument.

String mySearch = "tackoverflow";
String match1 = "Stackoverflow";

if (match1.contains(mySearhch)){
    //It contains the match
}

I hope it helps

答案 1 :(得分:0)

我有兴趣自己做类似这个要求的事情,所以我玩了一些东西。因此,此代码不仅仅是一个简短的代码段/快速修复程序。

我创建了自己的CustomArrayAdapter,扩展了BaseAdapter,主要基于ArrayAdapter的源代码。我没有实现添加,删除或修改适配器列表中的项目的方法,但这些方法可以很容易地从源中复制/调整(注意那些方法使用synchronize使适配器线程安全 - 是一定要遵循那个模式。)

关键是要创建自己的Filter,其中ArrayAdapter是一个内部私有类,因此它不仅仅是直接扩展ArrayAdapter的简单案例。

chntgomez的答案指向了正确的方向 - Filter ArrayAdapter仅使用startsWith(...)来匹配约束。它首先在完整字符串的开头尝试它,然后尝试拆分字符串(使用空格字符作为分隔符)来检查多字符串startWith(...)是否为约束(前缀)。

通过将startsWith(...)的使用更改为contains(...),您可以实现匹配&#39;在单个字符或字符序列上。分割任何多字符串的代码也可以删除,因为它不是必需的。

以下CustomArrayAdapter及其FilterActivity一起发布在原始问题中(显然正在将ArrayAdapter更改为CustomArrayAdapter)。

public class CustomArrayAdapter<T> extends BaseAdapter implements Filterable {

    private List<T> mObjects;
    private final Object mLock = new Object();
    private ArrayList<T> mOriginalValues;
    private Filter mFilter;
    private int mResource;
    private int mDropDownResource;
    private int mFieldId = 0;
    private boolean mNotifyOnChange = true;
    private Context mContext;
    private LayoutInflater mInflater;

    public CustomArrayAdapter(Context context, int resource, int textViewResourceId, T[] objects) {
        init(context, resource, textViewResourceId, Arrays.asList(objects));
    }

    private void init(Context context, int resource, int textViewResourceId, List<T> objects) {
        mContext = context;
        mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        mResource = mDropDownResource = resource;
        mObjects = objects;
        mFieldId = textViewResourceId;
    }

    @Override
    public void notifyDataSetChanged() {
        super.notifyDataSetChanged();
        mNotifyOnChange = true;
    }

    @Override
    public Filter getFilter() {
        if (mFilter == null) {
            mFilter = new CustomArrayFilter();
        }
        return mFilter;
    }

    @Override
    public int getCount() {
        return mObjects.size();
    }

    @Override
    public T getItem(int position) {
        return mObjects.get(position);
    }

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

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        return createViewFromResource(position, convertView, parent, mResource);
    }

    private View createViewFromResource(int position, View convertView, ViewGroup parent, int resource) {
        View view;
        TextView text;
        if (convertView == null) {
            view = mInflater.inflate(resource, parent, false);
        } else {
            view = convertView;
        }
        try {
            if (mFieldId == 0) {
                //  If no custom field is assigned, assume the whole resource is a TextView
                text = (TextView) view;
            } else {
                //  Otherwise, find the TextView field within the layout
                text = (TextView) view.findViewById(mFieldId);
            }
        } catch (ClassCastException e) {
            Log.e("CustomArrayAdapter", "You must supply a resource ID for a TextView");
            throw new IllegalStateException(
                    "CustomArrayAdapter requires the resource ID to be a TextView", e);
        }
        T item = getItem(position);
        if (item instanceof CharSequence) {
            text.setText((CharSequence)item);
        } else {
            text.setText(item.toString());
        }
        return view;
    }

    private class CustomArrayFilter extends Filter {

        @Override
        protected FilterResults performFiltering(CharSequence matchChars) {
            FilterResults results = new FilterResults();
            if (mOriginalValues == null) {
                synchronized (mLock) {
                    mOriginalValues = new ArrayList<T>(mObjects);
                }
            }
            if (matchChars == null || matchChars.length() == 0) {
                ArrayList<T> list;
                synchronized (mLock) {
                    list = new ArrayList<T>(mOriginalValues);
                }
                results.values = list;
                results.count = list.size();
            } else {
                String matchString = matchChars.toString().toLowerCase();
                ArrayList<T> values;
                synchronized (mLock) {
                    values = new ArrayList<T>(mOriginalValues);
                }
                final int count = values.size();
                final ArrayList<T> newValues = new ArrayList<T>();
                for (int i = 0; i < count; i++) {
                    final T value = values.get(i);
                    final String valueText = value.toString().toLowerCase();

                    if (valueText.contains(matchString)) {
                        newValues.add(value);
                    }
                }
                results.values = newValues;
                results.count = newValues.size();
            }
            return results;
        }

        @Override
        protected void publishResults(CharSequence constraint, FilterResults results) {
            mObjects = (List<T>) results.values;
            if (results.count > 0) {
                notifyDataSetChanged();
            } else {
                notifyDataSetInvalidated();
            }
        }

    }

}