将 AutoCompleteTextView 过滤器从 "startsWith" 更改为 "Contains"?
Change AutoCompleteTextView filter from "startsWith" to "Contains"?
我想更改 AutoCompleteTextView
中的默认过滤。默认过滤会查找以给定标记开头的所有字符串。我的项目要求过滤应该找到包含给定标记的所有字符串。
可能吗?
是的,有可能。
第一种方式:
您应该创建一个实现 ListAdapter and Filterable.
的自定义适配器
Filter 可以实现您的 "contains" 过滤逻辑。
并且您将此适配器设置为您的 AutoCompleteTextView 的适配器。
第二种方式:
如果您已经在使用 ArrayAdapter. You could just override it's getFilter() 方法。
感谢 Google 并搜索了两天,我找到了解决方案。正如 @torque203 所建议的,我已经实现了自己的自定义适配器。首先在适配器中定义一个新的XML文件来自定义Item:
autocomplete_item.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="Medium Text"
android:paddingLeft="8dp"
android:paddingRight="8dp"
android:paddingTop="16dp"
android:paddingBottom="16dp"
android:id="@+id/lbl_name" />
</RelativeLayout>
为您的名字创建新的 class:
名字
public class Names {
public String name;
}
名称适配器
public class NamesAdapter extends ArrayAdapter<Names> {
Context context;
int resource, textViewResourceId;
List<Names> items, tempItems, suggestions;
public NamesAdapter(Context context, int resource, int textViewResourceId, List<Names> items) {
super(context, resource, textViewResourceId, items);
this.context = context;
this.resource = resource;
this.textViewResourceId = textViewResourceId;
this.items = items;
tempItems = new ArrayList<Names>(items); // this makes the difference.
suggestions = new ArrayList<Names>();
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = convertView;
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(R.layout.autocomplete_item, parent, false);
}
Names names = items.get(position);
if (names != null) {
TextView lblName = (TextView) view.findViewById(R.id.lbl_name);
if (lblName != null)
lblName.setText(names.name);
}
return view;
}
@Override
public Filter getFilter() {
return nameFilter;
}
/**
* Custom Filter implementation for custom suggestions we provide.
*/
Filter nameFilter = new Filter() {
@Override
public CharSequence convertResultToString(Object resultValue) {
String str = ((Names) resultValue).name;
return str;
}
@Override
protected FilterResults performFiltering(CharSequence constraint) {
if (constraint != null) {
suggestions.clear();
for (Names names : tempItems) {
if (names.name.toLowerCase().contains(constraint.toString().toLowerCase())) {
suggestions.add(names);
}
}
FilterResults filterResults = new FilterResults();
filterResults.values = suggestions;
filterResults.count = suggestions.size();
return filterResults;
} else {
return new FilterResults();
}
}
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
List<Names> filterList = (ArrayList<Names>) results.values;
if (results != null && results.count > 0) {
clear();
for (Names names : filterList) {
add(names);
notifyDataSetChanged();
}
}
}
};
}
SearchActivity(或您的主要 activity)
....
List<Names> namesList = //your names list;
NamesAdapter namesAdapter = new NamesAdapter(
SearchActivity.this,
R.layout.activity_search,
R.id.lbl_name,
namesList
);
//set adapter into listStudent
autoCompleteTextView.setAdapter(namesAdapter);
autoCompleteTextView.showDropDown();
...
只是为了扩展 Caffe Latte 的精彩回答:
1)autoCompleteTextView.showDropDown();
不需要。
2) 要检索输入对象,可以使用:
//retrieve the input in the autoCompleteTextView
autoCompleteTextView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
//parent The AdapterView where the click happened.
//view The view within the AdapterView that was clicked (this will be a view provided by the adapter)
//position The position of the view in the adapter
//id The row id of the item that was clicked.
public void onItemClick(AdapterView<?> parent, View view, int position, long rowId) {
String selection =parent.getItemAtPosition(position).toString();
Toast.makeText(parent.getContext(),"" + selection,Toast.LENGTH_SHORT).show();
}
});
从父级检索到的对象必须实现了 toString() 方法。
// 试试这个
autoCompleteText.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View arg1, int position, long arg3) {
YourCustomModel YourFilterdSelectedModel = (YourCustomModel) adapterView.getItemAtPosition(position);
autoCompleteText.setText(str);
}
});
£
这对我有用
这是@Caffe Latte 发布的更简单的 Kotlin 版本。
您不需要自定义布局文件,只需使用默认布局文件 android.R.layout.simple_list_item_1
。
向此适配器提供任何 class,包括纯字符串。它将简单地使用 toString()
来确定显示文本。
import android.content.Context
import android.widget.ArrayAdapter
import android.widget.Filter
import androidx.annotation.IdRes
import androidx.annotation.LayoutRes
import java.util.*
class AutoCompleteAdapter(
context: Context,
@LayoutRes resource: Int,
@IdRes textViewResourceId: Int = 0,
internal var items: List<Any> = listOf()
)
: ArrayAdapter<Any>(context, resource, textViewResourceId, items) {
internal var tempItems: MutableList<Any> = mutableListOf()
internal var suggestions: MutableList<Any> = mutableListOf()
/**
* Custom Filter implementation for custom suggestions we provide.
*/
private var filter: Filter = object : Filter() {
override fun performFiltering(constraint: CharSequence?): FilterResults {
return if (constraint != null) {
suggestions.clear()
tempItems.forEach {
if (it.toString().toLowerCase(Locale.getDefault()).contains(constraint.toString().toLowerCase(Locale.getDefault()))) {
suggestions.add(it)
}
}
val filterResults = FilterResults()
filterResults.values = suggestions
filterResults.count = suggestions.size
filterResults
} else {
FilterResults()
}
}
override fun publishResults(constraint: CharSequence?, results: FilterResults) {
val filterList = results.values as? List<Any>
if (results.count > 0) {
clear()
filterList?.forEach {
add(it)
}.also {
notifyDataSetChanged()
}
}
}
}
init {
tempItems = items.toMutableList()
suggestions = ArrayList()
}
override fun getFilter(): Filter {
return filter
}
}
我想更改 AutoCompleteTextView
中的默认过滤。默认过滤会查找以给定标记开头的所有字符串。我的项目要求过滤应该找到包含给定标记的所有字符串。
可能吗?
是的,有可能。
第一种方式:
您应该创建一个实现 ListAdapter and Filterable.
的自定义适配器Filter 可以实现您的 "contains" 过滤逻辑。
并且您将此适配器设置为您的 AutoCompleteTextView 的适配器。
第二种方式:
如果您已经在使用 ArrayAdapter. You could just override it's getFilter() 方法。
感谢 Google 并搜索了两天,我找到了解决方案。正如 @torque203 所建议的,我已经实现了自己的自定义适配器。首先在适配器中定义一个新的XML文件来自定义Item:
autocomplete_item.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="Medium Text"
android:paddingLeft="8dp"
android:paddingRight="8dp"
android:paddingTop="16dp"
android:paddingBottom="16dp"
android:id="@+id/lbl_name" />
</RelativeLayout>
为您的名字创建新的 class:
名字
public class Names {
public String name;
}
名称适配器
public class NamesAdapter extends ArrayAdapter<Names> {
Context context;
int resource, textViewResourceId;
List<Names> items, tempItems, suggestions;
public NamesAdapter(Context context, int resource, int textViewResourceId, List<Names> items) {
super(context, resource, textViewResourceId, items);
this.context = context;
this.resource = resource;
this.textViewResourceId = textViewResourceId;
this.items = items;
tempItems = new ArrayList<Names>(items); // this makes the difference.
suggestions = new ArrayList<Names>();
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = convertView;
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(R.layout.autocomplete_item, parent, false);
}
Names names = items.get(position);
if (names != null) {
TextView lblName = (TextView) view.findViewById(R.id.lbl_name);
if (lblName != null)
lblName.setText(names.name);
}
return view;
}
@Override
public Filter getFilter() {
return nameFilter;
}
/**
* Custom Filter implementation for custom suggestions we provide.
*/
Filter nameFilter = new Filter() {
@Override
public CharSequence convertResultToString(Object resultValue) {
String str = ((Names) resultValue).name;
return str;
}
@Override
protected FilterResults performFiltering(CharSequence constraint) {
if (constraint != null) {
suggestions.clear();
for (Names names : tempItems) {
if (names.name.toLowerCase().contains(constraint.toString().toLowerCase())) {
suggestions.add(names);
}
}
FilterResults filterResults = new FilterResults();
filterResults.values = suggestions;
filterResults.count = suggestions.size();
return filterResults;
} else {
return new FilterResults();
}
}
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
List<Names> filterList = (ArrayList<Names>) results.values;
if (results != null && results.count > 0) {
clear();
for (Names names : filterList) {
add(names);
notifyDataSetChanged();
}
}
}
};
}
SearchActivity(或您的主要 activity)
....
List<Names> namesList = //your names list;
NamesAdapter namesAdapter = new NamesAdapter(
SearchActivity.this,
R.layout.activity_search,
R.id.lbl_name,
namesList
);
//set adapter into listStudent
autoCompleteTextView.setAdapter(namesAdapter);
autoCompleteTextView.showDropDown();
...
只是为了扩展 Caffe Latte 的精彩回答:
1)autoCompleteTextView.showDropDown();
不需要。
2) 要检索输入对象,可以使用:
//retrieve the input in the autoCompleteTextView
autoCompleteTextView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
//parent The AdapterView where the click happened.
//view The view within the AdapterView that was clicked (this will be a view provided by the adapter)
//position The position of the view in the adapter
//id The row id of the item that was clicked.
public void onItemClick(AdapterView<?> parent, View view, int position, long rowId) {
String selection =parent.getItemAtPosition(position).toString();
Toast.makeText(parent.getContext(),"" + selection,Toast.LENGTH_SHORT).show();
}
});
从父级检索到的对象必须实现了 toString() 方法。
// 试试这个
autoCompleteText.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View arg1, int position, long arg3) {
YourCustomModel YourFilterdSelectedModel = (YourCustomModel) adapterView.getItemAtPosition(position);
autoCompleteText.setText(str);
}
});
£ 这对我有用
这是@Caffe Latte 发布的更简单的 Kotlin 版本。
您不需要自定义布局文件,只需使用默认布局文件 android.R.layout.simple_list_item_1
。
向此适配器提供任何 class,包括纯字符串。它将简单地使用 toString()
来确定显示文本。
import android.content.Context
import android.widget.ArrayAdapter
import android.widget.Filter
import androidx.annotation.IdRes
import androidx.annotation.LayoutRes
import java.util.*
class AutoCompleteAdapter(
context: Context,
@LayoutRes resource: Int,
@IdRes textViewResourceId: Int = 0,
internal var items: List<Any> = listOf()
)
: ArrayAdapter<Any>(context, resource, textViewResourceId, items) {
internal var tempItems: MutableList<Any> = mutableListOf()
internal var suggestions: MutableList<Any> = mutableListOf()
/**
* Custom Filter implementation for custom suggestions we provide.
*/
private var filter: Filter = object : Filter() {
override fun performFiltering(constraint: CharSequence?): FilterResults {
return if (constraint != null) {
suggestions.clear()
tempItems.forEach {
if (it.toString().toLowerCase(Locale.getDefault()).contains(constraint.toString().toLowerCase(Locale.getDefault()))) {
suggestions.add(it)
}
}
val filterResults = FilterResults()
filterResults.values = suggestions
filterResults.count = suggestions.size
filterResults
} else {
FilterResults()
}
}
override fun publishResults(constraint: CharSequence?, results: FilterResults) {
val filterList = results.values as? List<Any>
if (results.count > 0) {
clear()
filterList?.forEach {
add(it)
}.also {
notifyDataSetChanged()
}
}
}
}
init {
tempItems = items.toMutableList()
suggestions = ArrayList()
}
override fun getFilter(): Filter {
return filter
}
}