I have set up a small tutorial to do that
http://drzon.net/how-to-create-a-clearable-autocomplete-dropdown-with-autocompletetextview/
Overview
I had to replace the SearchView
with AutoCompleteTextView
as suggested.
First, create an adapter. In my case it was a JSONObject
ArrayAdapter. The data I wanted to display in the drop down was a venue name and venue address. Notice that the adapter must be Filtarable
and override getFilter()
// adapter for the search dropdown auto suggest
ArrayAdapter<JSONObject> searchAdapter = new ArrayAdapter<JSONObject>(this, android.R.id.text1) {
private Filter filter;
public View getView(final int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = this.getLayoutInflater().inflate(R.layout.search_item, parent, false);
}
TextView venueName = (TextView) convertView.findViewById(R.id.search_item_venue_name);
TextView venueAddress = (TextView) convertView.findViewById(R.id.search_item_venue_address);
final JSONObject venue = this.getItem(position);
convertView.setTag(venue);
try {
CharSequence name = highlightText(venue.getString("name"));
CharSequence address = highlightText(venue.getString("address"));
venueName.setText(name);
venueAddress.setText(address);
}
catch (JSONException e) {
Log.i(Consts.TAG, e.getMessage());
}
return convertView;
}
@Override
public Filter getFilter() {
if (filter == null) {
filter = new VenueFilter();
}
return filter;
}
};
Here is the custom VenueFilter
:
private class VenueFilter extends Filter {
@Override
protected FilterResults performFiltering(CharSequence constraint) {
List<JSONObject> list = new ArrayList<JSONObject>(venues);
FilterResults result = new FilterResults();
String substr = constraint.toString().toLowerCase();
if (substr == null || substr.length() == 0) {
result.values = list;
result.count = list.size();
} else {
final ArrayList<JSONObject> retList = new ArrayList<JSONObject>();
for (JSONObject venue : list) {
try {
if (venue.getString("name").toLowerCase().contains(constraint) || venue.getString("address").toLowerCase().contains(constraint) ||
{
retList.add(venue);
}
} catch (JSONException e) {
Log.i(Consts.TAG, e.getMessage());
}
}
result.values = retList;
result.count = retList.size();
}
return result;
}
@SuppressWarnings("unchecked")
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
searchAdapter.clear();
if (results.count > 0) {
for (JSONObject o : (ArrayList<JSONObject>) results.values) {
searchAdapter.add(o);
}
}
}
}
Now set up the layout for the search box (actionbar_search.xml
) :
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="match_parent"
android:layout_gravity="fill_horizontal"
android:focusable="true" >
<AutoCompleteTextView
android:id="@+id/search_box"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:dropDownVerticalOffset="5dp"
android:dropDownWidth="wrap_content"
android:inputType="textAutoComplete|textAutoCorrect"
android:popupBackground="@color/white"
android:textColor="#FFFFFF" >
</AutoCompleteTextView>
</RelativeLayout>
And the layout for individual drop down item (venue name and venue address). This one looks bad, you'll have to customize it:
<?xml version="1.0" encoding="UTF-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textAlignment="gravity" >
<TextView
android:id="@+id/search_item_venue_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/cyan"
android:layout_gravity="right" />
<TextView
android:id="@+id/search_item_venue_address"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toStartOf="@+id/search_item_venue_name"
android:gravity="right"
android:textColor="@color/white" />
</RelativeLayout>
Next we want to put it in the action bar
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActionBar actionBar = getSupportActionBar();
actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM | ActionBar.DISPLAY_USE_LOGO | ActionBar.DISPLAY_SHOW_HOME
| ActionBar.DISPLAY_HOME_AS_UP);
LayoutInflater inflater = (LayoutInflater)this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View v = inflater.inflate(R.layout.actionbar_search, null);
AutoCompleteTextView textView = (AutoCompleteTextView) v.findViewById(R.id.search_box);
textView.setAdapter(searchAdapter);
textView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// do something when the user clicks
}
});
actionBar.setCustomView(v);
}
That's about it, I still have some stuff to figure out :
- This puts an "always there" search in the action bar, I want it to be like the
SearchView
widget - a magnifier glass that opens up to a search box when you click it (and has a little X
button to dismiss it and go back to normal)
- Haven't figured out how to customize the drop down box yet, for example, the Gmail one seems to have shadow, mine is just flat, change the color of the line delimiters etc...
Overall this saves all the overhead of creating a searchable activity. Please add if you know how to customize it etc.