Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Autocomplete textbox highlighting the typed character in the suggestion list

I have been working on AutoCompleteTextView. I was able to get the suggestion and all in the drop down list as we type.

So far

My question is: Can we highlight the typed character in the suggestion drop down list?

like image 677
Anupam Avatar asked Feb 27 '13 18:02

Anupam


People also ask

How do I create an autocomplete text view field in XML?

In android, we can create an AutoCompleteTextView control in two ways either manually in an XML file or create it in the Activity file programmatically. First we create a new project by following the below steps: Click on File, then New => New Project. After that include the Kotlin support and click on next.

Which method is used for filling the data to AutoCompleteTextView?

XML attributes Defines the number of characters that the user must type before completion suggestions are displayed in a drop down menu. View to anchor the auto-complete dropdown to.

How do I get text from AutoCompleteTextView?

OnItemClickListener and set onItemClickListener() on the AutoCompleteTextView to get the user selected item value from the list. Notice that while using the ArrayAdapter , we have provided a layout object as argument android.

What is used of setThreshold () method?

setThreshold(int threshold): This method is used to set threshold value that help us to start the searching from a specific character. In this we set int type value used to specify the threshold .


2 Answers

I have achieved the functionality. The solution is as follows:

AutoCompleteAdapter.java

public class AutoCompleteAdapter extends ArrayAdapter<String> implements
        Filterable {

    private ArrayList<String> fullList;
    private ArrayList<String> mOriginalValues;
    private ArrayFilter mFilter;
    LayoutInflater inflater;
    String text = "";

    public AutoCompleteAdapter(Context context, int resource,
            int textViewResourceId, List<String> objects) {

        super(context, resource, textViewResourceId, objects);
        fullList = (ArrayList<String>) objects;
        mOriginalValues = new ArrayList<String>(fullList);
        inflater = LayoutInflater.from(context);

    }

    @Override
    public int getCount() {
        return fullList.size();
    }

    @Override
    public String getItem(int position) {
        return fullList.get(position);
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View view = convertView;
        // tvViewResourceId = (TextView) view.findViewById(android.R.id.text1);
        String item = getItem(position);
        Log.d("item", "" + item);
        if (convertView == null) {
            convertView = view = inflater.inflate(
                    android.R.layout.simple_dropdown_item_1line, null);
        }
        // Lookup view for data population
        TextView myTv = (TextView) convertView.findViewById(android.R.id.text1);
        myTv.setText(highlight(text, item));
        return view;
    }

    @Override
    public Filter getFilter() {
        if (mFilter == null) {
            mFilter = new ArrayFilter();
        }
        return mFilter;
    }

    private class ArrayFilter extends Filter {
        private Object lock;

        @Override
        protected FilterResults performFiltering(CharSequence prefix) {
            FilterResults results = new FilterResults();
            if (prefix != null) {
                text = prefix.toString();
            }
            if (mOriginalValues == null) {
                synchronized (lock) {
                    mOriginalValues = new ArrayList<String>(fullList);
                }
            }

            if (prefix == null || prefix.length() == 0) {
                synchronized (lock) {
                    ArrayList<String> list = new ArrayList<String>(
                            mOriginalValues);
                    results.values = list;
                    results.count = list.size();
                }
            } else {
                final String prefixString = prefix.toString().toLowerCase();
                ArrayList<String> values = mOriginalValues;
                int count = values.size();

                ArrayList<String> newValues = new ArrayList<String>(count);

                for (int i = 0; i < count; i++) {
                    String item = values.get(i);
                    if (item.toLowerCase().contains(prefixString)) {
                        newValues.add(item);
                    }

                }

                results.values = newValues;
                results.count = newValues.size();
            }

            return results;
        }

        @SuppressWarnings("unchecked")
        @Override
        protected void publishResults(CharSequence constraint,
                FilterResults results) {

            if (results.values != null) {
                fullList = (ArrayList<String>) results.values;
            } else {
                fullList = new ArrayList<String>();
            }
            if (results.count > 0) {
                notifyDataSetChanged();
            } else {
                notifyDataSetInvalidated();
            }
        }

    }

    public static CharSequence highlight(String search, String originalText) {
        // ignore case and accents
        // the same thing should have been done for the search text
        String normalizedText = Normalizer
                .normalize(originalText, Normalizer.Form.NFD)
                .replaceAll("\\p{InCombiningDiacriticalMarks}+", "")
                .toLowerCase(Locale.ENGLISH);

        int start = normalizedText.indexOf(search.toLowerCase(Locale.ENGLISH));
        if (start < 0) {
            // not found, nothing to to
            return originalText;
        } else {
            // highlight each appearance in the original text
            // while searching in normalized text
            Spannable highlighted = new SpannableString(originalText);
            while (start >= 0) {
                int spanStart = Math.min(start, originalText.length());
                int spanEnd = Math.min(start + search.length(),
                        originalText.length());

                highlighted.setSpan(new ForegroundColorSpan(Color.BLUE),
                        spanStart, spanEnd, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

                start = normalizedText.indexOf(search, spanEnd);
            }

            return highlighted;
        }
    }
}

MainActivity.java

public class MainActivity extends Activity {

    String[] languages = { "C", "C++", "Java", "C#", "PHP", "JavaScript",
            "jQuery", "AJAX", "JSON" };

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);


        List<String> wordList = new ArrayList<String>(); 
        Collections.addAll(wordList, languages); 
        AutoCompleteAdapter adapter = new AutoCompleteAdapter(this,
                android.R.layout.simple_dropdown_item_1line,
                android.R.id.text1,wordList);
        AutoCompleteTextView acTextView = (AutoCompleteTextView) findViewById(R.id.languages);
        acTextView.setThreshold(1);
        acTextView.setAdapter(adapter);
    }
}

Working like charm!

Enjoy!

like image 147
vadher jitendra Avatar answered Sep 17 '22 13:09

vadher jitendra


I reckon that should be possible, provided you know the index/indices of the character(s) the user typed last. You can then use a SpannableStringBuilder and set a ForegroundColorSpan and BackgroundColorSpan to give the character(s) the appearance of a highlight.

The idea looks somewhat like this:

// start & end of the highlight
int start = ...;
int end = ...;
SpannableStringBuilder builder = new SpannableStringBuilder(suggestionText);
// set foreground color (text color) - optional, you may not want to change the text color too
builder.setSpan(new ForegroundColorSpan(Color.RED), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); 
// set background color
builder.setSpan(new BackgroundColorSpan(Color.YELLOW), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
// set result to AutoCompleteTextView
autocompleteTextview.setText(builder);

Note that the 'highlight' will remain as long as you don't type another character. You may want to remove the highlight when e.g. the user changes the cursor position in the AutoCompleteTextView, but I'll leave that up to you.

like image 32
MH. Avatar answered Sep 21 '22 13:09

MH.