我想在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
}
});
}
}
答案 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
及其Filter
与Activity
一起发布在原始问题中(显然正在将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();
}
}
}
}