Android 部分单词搜索的Searchview

Android 部分单词搜索的Searchview,android,searchview,Android,Searchview,我想在Android中实现一个SearchView,用于部分单词搜索。 我已经做了以下的搜索机制,如何获得部分单词搜索功能 如果我搜索“stackover..”,stackoverflow会出现,但如果我搜索“tackover..”,stackoverflow不会出现,我需要它搜索单词中的部分匹配项 package jagranerp.myapplication; import java.util.ArrayList; import java.util.HashMap; import and

我想在Android中实现一个
SearchView
,用于部分单词搜索。 我已经做了以下的搜索机制,如何获得部分单词搜索功能

如果我搜索“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
            }
        });
    }

}
包jagranerp.myapplication;
导入java.util.ArrayList;
导入java.util.HashMap;
导入android.app.Activity;
导入android.os.Bundle;
导入android.text.Editable;
导入android.text.TextWatcher;
导入android.widget.ArrayAdapter;
导入android.widget.EditText;
导入android.widget.ListView;
公共类MainActivity扩展了活动{
//列表视图
私有ListView lv;
//列表视图适配器
阵列适配器;
//搜索编辑文本
编辑文本输入搜索;
//Listview的ArrayList
ArrayList产品列表;
@凌驾
创建时的公共void(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//列表视图数据
字符串产品[]={“戴尔Inspiron”、“HTC One X”、“HTC Wildfire S”、“HTC Sense”、“HTC Sensation XE”,
“iPhone 4S”、“三星Galaxy Note 800”,
“三星Galaxy S3”、“MacBook Air”、“MacMini”、“MacBook Pro”};
lv=(ListView)findViewById(R.id.list\u视图);
inputSearch=(EditText)findViewById(R.id.inputSearch);
//向listview添加项目
适配器=新阵列适配器(此,R.layout.list_项,R.id.product_名称,产品);
低压设置适配器(适配器);
/**
*启用搜索筛选器
* */
inputSearch.addTextChangedListener(新的TextWatcher(){
@凌驾
public void onTextChanged(字符序列cs、int arg1、int arg2、int arg3){
//当用户更改文本时
MainActivity.this.adapter.getFilter().filter(cs);
}
@凌驾
更改前的公共void(字符序列arg0、int arg1、int arg2、,
int arg3){
//TODO自动生成的方法存根
}
@凌驾
public void PostTextChanged(可编辑arg0){
//TODO自动生成的方法存根
}
});
}
}
filter()方法将返回关键字“cs”的一致性。在本例中,“Stackoverflow”将与“tackover”不匹配,因为如果“Stackoverflow”以“tackover”开头,则比较将求值。因为它将返回false,所以它不会通过过滤器

我不太清楚过滤器是如何工作的,但是您可以使用String类的contains(String arg)方法。如果找到给定参数的任何匹配项,此方法将返回true

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

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

我希望这能有所帮助

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

我创建了自己的
CustomArrayAdapter
,它扩展了
BaseAdapter
,主要基于的源代码。我还没有实现添加、删除或修改适配器列表中项目的方法,但这些方法可以很容易地从源代码复制/改编(请注意,这些方法使用
synchronize
确保适配器线程安全-请确保遵循该模型)

关键是创建自己的
过滤器
,它在
ArrayAdapter
中是一个内部私有类,因此它不仅仅是直接扩展
ArrayAdapter
的简单情况

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

通过将
startsWith(…)
的用法更改为
contains(…)
可以实现单个字符或字符序列的“匹配”。分割任何多字字符串的代码也可以删除,因为这不是必需的

以下
CustomArrayAdapter
及其
Filter
与原始问题中发布的
Activity
配合使用(显然将
ArrayAdapter
改为
CustomArrayAdapter

公共类CustomArrayAdapter扩展BaseAdapter实现可过滤{
私有列表对象;
私有最终对象mLock=新对象();
私人ArrayList mOriginalValues;
专用过滤器;
私人国际资源;
私有int mDropDownResource;
私有int mFieldId=0;
私有布尔值mNotifyOnChange=true;
私有上下文;
私人停车场;
公共CustomArrayAdapter(上下文上下文、int资源、int textViewResourceId、T[]对象){
init(context,resource,textViewResourceId,Arrays.asList(objects));
}
私有void init(上下文上下文、int资源、int textViewResourceId、列表对象){
mContext=上下文;
mInflater=(LayoutInflater)context.getSystemService(context.LAYOUT\u充气机\u服务);
mResource=mdropdownsource=resource;
mObjects=对象;
mFieldId=textViewResourceId;
}
@凌驾
public void notifyDataSetChanged(){
super.notifyDataSetChanged();
mNotifyOnChange=true;
}
@凌驾
公共过滤器getFilter(){
if(mFilter==null){
mFilter=新的CustomArrayFilter();
}
返回过滤器;
}
@凌驾
public int getCount(){
返回mObjects.size();
}
@凌驾
公共T getItem(内部位置){
返回mObjects.get(位置);
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();
            }
        }

    }

}