Custom AutoCompleteTextView behavior

前端 未结 4 971
再見小時候
再見小時候 2020-12-19 02:45

Out of the box, the AutoCompleteTextView widget does not seem to be able to match the input string in the middle of a list value - the matches are always made a

相关标签:
4条回答
  • 2020-12-19 03:00
    public class AutoCompleteAdapter <T> extends ArrayAdapter<T> implements Filterable {
        private List <T> listObjects;
        List<T> suggestions = new ArrayList<>();
        private Context context;
        public AutoCompleteAdapter(Context context, List<T> listObjects) {
            super(context, R.layout.list_item_simple, listObjects);
            this.listObjects = new ArrayList<>(listObjects);
            this.context = context;
        }
        private Filter mFilter = new Filter(){
            @Override
            protected FilterResults performFiltering(CharSequence constraint) {
                FilterResults filterResults = new FilterResults();
                if(constraint != null) {
                suggestions.clear();
                    for(T object : listObjects){  
                        if(object.toString().toLowerCase().contains(constraint.toString().toLowerCase())){                        suggestions.add(object);
                    }
                }
    
                filterResults.values = suggestions;
                filterResults.count = suggestions.size();
            }
            return filterResults;
        }
    
        @Override
        protected void publishResults(CharSequence constraint, FilterResults results) {
            if(results == null){
                return;
            }
            List<T> filteredList = (List<T>) results.values;
            if(results.count > 0) {
                clear();
                for (T filteredObject : filteredList) {
                    add(filteredObject);
                }
                notifyDataSetChanged();
            }
        }
    };
    @Override
    public Filter getFilter() {
        return mFilter;
    }
    private static class ViewHolder {
        TextView title;
    }
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        Object listObject = getItem(position);
        final ViewHolder viewHolder; // view lookup cache stored in tag
        if (convertView == null) {
            viewHolder = new ViewHolder();
            LayoutInflater inflater = LayoutInflater.from(getContext());
            convertView = inflater.inflate(R.layout.list_item_simple, parent, false);
            viewHolder.title = (TextView) convertView.findViewById(R.id.title);
            convertView.setTag(viewHolder);
        } else {
            viewHolder = (ViewHolder) convertView.getTag();
        }
        viewHolder.title.setText(listObject.toString());
        return convertView;
    }
    

    }

    0 讨论(0)
  • 2020-12-19 03:02

    My advice would be to parse the string into a character array. Then iterate each character until the string is found.

    For example lets say your search wanted to return all words with "ate" in them and the word list was...

    state trait berate late

    Your algorithm should go something like this

    Take the string and parse it into a character array Loop through the array and find the first "correct character" (in our example its 'a') Once that character is found check the next character, keep checking each character for a match until the value being searched for is complete. If the character is not a match exit the array iteration and go to the next word.

    0 讨论(0)
  • 2020-12-19 03:10

    Old question, but still relevant. Following the guidance of a few other questions implemented a custom adapter using filterable. I made a simple generic adapter that searches with contains. Quick notes on it:

    I'm using butterknife, but easy to do the viewHolder with findviewbyid.

    The layout R.layout.list_item_simple is a simple layout with the textview R.id.text_view_simple.

    The object needs a toString that will be compared.

    public class SimpleContainsAutocompleteAdapter <T> extends ArrayAdapter<T> implements Filterable {
        private List <T> listObjects;
        List<T> suggestions = new ArrayList<>();
        private int resource;
    
        private Filter mFilter = new Filter(){
            @Override
            protected FilterResults performFiltering(CharSequence constraint) {
                FilterResults filterResults = new FilterResults();
    
                if(constraint != null) {
                    suggestions.clear();
                    for(T object : listObjects){
                        if(object.toString().toLowerCase().contains(constraint.toString().toLowerCase())){
                            suggestions.add(object);
                        }
                    }
    
                    filterResults.values = suggestions;
                    filterResults.count = suggestions.size();
                }
    
                return filterResults;
            }
    
            @Override
            protected void publishResults(CharSequence contraint, FilterResults results) {
                if(results == null){
                    return;
                }
    
                List<T> filteredList = (List<T>) results.values;
                if(results.count > 0) {
                    clear();
                    for (T filteredObject : filteredList) {
                        add(filteredObject);
                    }
                    notifyDataSetChanged();
                }
            }
        };
    
        public SimpleContainsAutocompleteAdapter(Context context, List<T> listObjects) {
            super(context, R.layout.list_item_simple, listObjects);
            this.listObjects = new ArrayList<>(listObjects);
            this.resource = R.layout.list_item_simple;
        }
    
        @Override
        public Filter getFilter() {
            return mFilter;
        }
    
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            Object listObject = getItem(position);
            viewHolder holder;
            if(convertView != null) {
                holder = (viewHolder) convertView.getTag();
            }else{
                convertView = LayoutInflater.from(getContext()).inflate(resource, parent, false);
                holder = new viewHolder(convertView);
                convertView.setTag(holder);
            }
    
            holder.name.setText(listObject.toString());
    
            return convertView;
        }
    
    
        static class viewHolder {
            @InjectView(R.id.text_view_simple) TextView name;
    
            public viewHolder(View view) {
                ButterKnife.inject(this, view);
            }
        }
    }
    
    0 讨论(0)
  • 2020-12-19 03:19

    You would need to write a custom Filter class and implement the performFiltering method yourself. This method takes a CharSequence argument, which you can use to perform whatever String operations you need in order to generate a list of matches from your dataset (in your case, you could use String.contains instead of String.startsWith). The performFiltering function is not run on the UI thread.

    You then return your list of matches as a FilterResults object, which contains an Object values (your list of matches, probably an ArrayList) and an int count which is the size of your list of matches.

    Finally, implement the publishResults callback method, which returns once the worker thread has generated the list of matches, allowing you to call notifyDataSetChanged on your AutoCompleteTextView's adapter so that it can display the results.

    0 讨论(0)
提交回复
热议问题