将 AutoCompleteTextView 过滤器从“startsWith”更改为“Contains”?

问题描述 投票:0回答:6

我想更改

AutoCompleteTextView
中的默认过滤。默认过滤会查找以给定标记开头的所有字符串。我的项目要求过滤应找到包含给定标记的所有字符串。

可能吗?

android autocompletetextview
6个回答
24
投票

我找到了解决方案,感谢谷歌和搜索了两天。正如 @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>

为您的名字创建新类别:

名字

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();
                }
            }
        }
    };
}

搜索活动(或您的主要活动)

....
   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();
...

7
投票

这是 @Caffe Latte 发布的更简单的 Kotlin 版本。

您不需要自定义布局文件,只需使用默认的

android.R.layout.simple_list_item_1

为此适配器提供任何类,包括普通的字符串。它将简单地使用

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
    }
}

0
投票

是的,这是可能的。

第一种方法:

您应该创建一个实现 ListAdapterFilterable 的自定义适配器。

Filter可以实现您的“包含”过滤逻辑。

然后将此适配器设置为 AutoCompleteTextView 的适配器。

第二种方式:

如果您已经在使用 ArrayAdapter。您可以覆盖它的 getFilter() 方法。


0
投票

只是为了扩展拿铁咖啡的好答案:

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() 方法。


0
投票

//试试这个

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);
    }
});

£ 这对我有用


0
投票

这对我来说效果很好。我使用标准 ArrayAdapter 来处理 4 个 AutoCompleteTextView。默认情况下,这使用 STARTS-WITH 逻辑。我只想将其中之一更改为包含逻辑。这是有效的代码。

旧代码只是 IF 块中的内容;新代码位于 ELSE 块中,后面是私有类 ContainsArrayAdapter...

        ArrayAdapter<String> dropdownAdapter;
        if (autoCompleteTextView.getId() != R.id.HotspotList) {
            // Create new adapter for dropdown layout using default STARTS-WITH searching.
            dropdownAdapter = new ArrayAdapter<>(getApplicationContext(), R.layout.simple_dropdown_item, adapterList);
            // Set Adapter on AutoCompleteTextView
            autoCompleteTextView.setAdapter(dropdownAdapter);
        } else {
            // Create new adapter which uses CONTAINS searching instead of STARTS-WITH. 14-Aug-2023
            dropdownAdapter = new ContainsArrayAdapter(getApplicationContext(), R.layout.simple_dropdown_item, (ArrayList<String>) adapterList);
            // Set Adapter on AutoCompleteTextView
            autoCompleteTextView.setAdapter(dropdownAdapter);
        }

这是上面引用的 ArrayAdapter 扩展私有类。

private class ContainsArrayAdapter extends ArrayAdapter<String> {

    private List<String> originalList;
    private List<String> filteredList;
    public ContainsArrayAdapter(@NonNull Context context, int resource, @NonNull ArrayList<String> objects) {
        super(context, resource, objects);
        this.originalList = new ArrayList<>(objects);
        this.filteredList = new ArrayList<>(objects);
    }

    @NonNull
    @Override
    public Filter getFilter() {
        return new Filter() {
            @Override
            protected FilterResults performFiltering(CharSequence charSequence) {
                FilterResults filterResults = new FilterResults();
                if (charSequence == null || charSequence.length() == 0) {
                    filterResults.values = originalList;
                    filterResults.count = originalList.size();
                } else {
                    List<String> tempList = new ArrayList<>();
                    for (String item : originalList) {
                        if (item.toLowerCase().contains(charSequence.toString().toLowerCase())) {
                            tempList.add(item);
                        }
                    }
                    filterResults.values = tempList;
                    filterResults.count = tempList.size();
                }
                return filterResults;
            }

            @Override
            protected void publishResults(CharSequence charSequence, FilterResults filterResults) {
                filteredList = (List<String>) filterResults.values;
                clear();
                addAll(filteredList);
                notifyDataSetChanged();
            }
        };
    }

很简单。我测试没发现什么问题。

© www.soinside.com 2019 - 2024. All rights reserved.