How can I build a search bar where while I'm typing the results are shown in the ListView in which I'm searching?
For example, I have a list view with 20 strings. I press the search key and appears the bar. I want when I type 3 words or more the search starts running showing the results in the list view (as a filter: only shows the strings in the list that matching what I type)
I believe this is what you are looking for:
http://www.java2s.com/Code/Android/2D-Graphics/ShowsalistthatcanbefilteredinplacewithaSearchViewinnoniconifiedmode.htm
Have your Activity implement SearchView.OnQueryTextListener
and add the following methods:
public boolean onQueryTextChange(String newText) {
if (TextUtils.isEmpty(newText)) {
mListView.clearTextFilter();
} else {
mListView.setFilterText(newText.toString());
}
return true;
}
public boolean onQueryTextSubmit(String query) {
return false;
}
You can't do this with the search bar. But the listview has a possibility to filter on key pressed, like it is done in the contacts. The user simply starts typing and the list gets filtered then. Filtering is not really like searching. If you list contains the word foo somewhere and you type oo foo will be filtered out, but if you type fo it will stay even if the list item is call bar foo.
You simply have to enable it:
ListView lv = getListView();
lv.setTextFilterEnabled(true);
I don't know how this is done if you don't have a hardware keyboard. I'm using the droid and starting to type starts the list to filter and to show only matching results.
I used an EditText to do the job.
First I created two copies of the array to hold the list of data to search:
List<Map<String,String>> vehicleinfo;
List<Map<String,String>> vehicleinfodisplay;
Once I've got my list data from somewhere, I copy it:
for(Map<String,String>map : vehicleinfo)
{
vehicleinfodisplay.add(map);
}
and use a SimpleAdapter to display the display (copied) version of my data:
String[] from={"vehicle","dateon","dateoff","reg"};
int[] to={R.id.vehicle,R.id.vehicledateon,R.id.vehicledateoff,R.id.vehiclereg};
listadapter=new SimpleAdapter(c,vehicleinfodisplay,R.layout.vehiclelistrow,from,to);
vehiclelist.setAdapter(listadapter);
Then I added a TextWatcher to the EditText which responds to an afterTextChanged event by clearing the display version of the list and then adding back only the items from the other list that meet the search criteria (in this case the "reg" field contains the search string). Once the display list is populated with the filtered list, I just call notifyDataSetChanged on the list's SimpleAdapter.
searchbox.addTextChangedListener(new TextWatcher()
{
#Override
public void afterTextChanged(Editable s)
{
vehicleinfodisplay.clear();
String search=s.toString();
for(Map<String,String>map : vehicleinfo)
{
if(map.get("reg").toLowerCase().contains(search.toLowerCase()))
vehicleinfodisplay.add(map);
listadapter.notifyDataSetChanged();
}
};
... other overridden methods can go here ...
});
Hope this is helpful to someone.
Use following code to implement search and filter list in android:
SearchAndFilterList.java
public class SearchAndFilterList extends Activity {
private ListView mSearchNFilterLv;
private EditText mSearchEdt;
private ArrayList<String> mStringList;
private ValueAdapter valueAdapter;
private TextWatcher mSearchTw;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_search_and_filter_list);
initUI();
initData();
valueAdapter=new ValueAdapter(mStringList,this);
mSearchNFilterLv.setAdapter(valueAdapter);
mSearchEdt.addTextChangedListener(mSearchTw);
}
private void initData() {
mStringList=new ArrayList<String>();
mStringList.add("one");
mStringList.add("two");
mStringList.add("three");
mStringList.add("four");
mStringList.add("five");
mStringList.add("six");
mStringList.add("seven");
mStringList.add("eight");
mStringList.add("nine");
mStringList.add("ten");
mStringList.add("eleven");
mStringList.add("twelve");
mStringList.add("thirteen");
mStringList.add("fourteen");
mSearchTw=new TextWatcher() {
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
valueAdapter.getFilter().filter(s);
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
}
#Override
public void afterTextChanged(Editable s) {
}
};
}
private void initUI() {
mSearchNFilterLv=(ListView) findViewById(R.id.list_view);
mSearchEdt=(EditText) findViewById(R.id.txt_search);
}
}
Custom Value adapter:
ValueAdapter.java
public class ValueAdapter extends BaseAdapter implements Filterable{
private ArrayList<String> mStringList;
private ArrayList<String> mStringFilterList;
private LayoutInflater mInflater;
private ValueFilter valueFilter;
public ValueAdapter(ArrayList<String> mStringList,Context context) {
this.mStringList=mStringList;
this.mStringFilterList=mStringList;
mInflater=LayoutInflater.from(context);
getFilter();
}
//How many items are in the data set represented by this Adapter.
#Override
public int getCount() {
return mStringList.size();
}
//Get the data item associated with the specified position in the data set.
#Override
public Object getItem(int position) {
return mStringList.get(position);
}
//Get the row id associated with the specified position in the list.
#Override
public long getItemId(int position) {
return position;
}
//Get a View that displays the data at the specified position in the data set.
#Override
public View getView(int position, View convertView, ViewGroup parent) {
Holder viewHolder;
if(convertView==null) {
viewHolder=new Holder();
convertView=mInflater.inflate(R.layout.list_item,null);
viewHolder.nameTv=(TextView)convertView.findViewById(R.id.txt_listitem);
convertView.setTag(viewHolder);
}else{
viewHolder=(Holder)convertView.getTag();
}
viewHolder.nameTv.setText(mStringList.get(position).toString());
return convertView;
}
private class Holder{
TextView nameTv;
}
//Returns a filter that can be used to constrain data with a filtering pattern.
#Override
public Filter getFilter() {
if(valueFilter==null) {
valueFilter=new ValueFilter();
}
return valueFilter;
}
private class ValueFilter extends Filter {
//Invoked in a worker thread to filter the data according to the constraint.
#Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults results=new FilterResults();
if(constraint!=null && constraint.length()>0){
ArrayList<String> filterList=new ArrayList<String>();
for(int i=0;i<mStringFilterList.size();i++){
if(mStringFilterList.get(i).contains(constraint)) {
filterList.add(mStringFilterList.get(i));
}
}
results.count=filterList.size();
results.values=filterList;
}else{
results.count=mStringFilterList.size();
results.values=mStringFilterList;
}
return results;
}
//Invoked in the UI thread to publish the filtering results in the user interface.
#SuppressWarnings("unchecked")
#Override
protected void publishResults(CharSequence constraint,
FilterResults results) {
mStringList=(ArrayList<String>) results.values;
notifyDataSetChanged();
}
}
}
activity_search_and_filter_list.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<EditText
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="#+id/txt_search"
tools:context=".SearchAndFilterList"
android:hint="Enter text to search" />
<ListView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/list_view"
android:layout_below="#+id/txt_search"></ListView>
</RelativeLayout>
list_item.xml
<?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" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/txt_listitem"/>
</RelativeLayout>
AndroidManifext.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.searchandfilterlistview"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="15" />
<application
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name=".SearchAndFilterList"
android:label="#string/title_activity_search_and_filter_list" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
I hope this code will will helpful to implement custom search and filter listview
The best way is to use the built in search bar or SearchManager by overriding onSearchRequested in a searchable activity. You can set a datasource to search on to get the automatic drop down of results or you can just take in the input from the user and search after. Here is a good overview of SearchManager is a
Plus there is a working demo in the API Demos project com.example.android.apis.app.SearchQueryResult
#Override
public boolean onSearchRequested() {
Related
I'm having some problem with the search bar.
i have an app that have a Listview in some activity, the listview have only strings inside it. I'v wanted to add a search functionality into this activity.
In the last few days i was searching over the web for some example of how to do that, and i founded a lot of guides and explanations of how to create a search bar, and none of them works in my app correctly and in most of them there is no explanation of the logic behind what is going on there.
Is there any simple guide/tutorial that can explain how to create a search bar (doesn't matter if it will be on the Action bar, or in the layout) that will reduce the already existing listview of strings into smaller list? (For example if you type the letter "a" so all the strings inside the listview that contains the letter "a" will be shown).
Thanks in advance!
Following Code will help your to filter the content of your listView.
Create SearcView using the layout like this:
<ImageView
android:id="#+id/icon_search"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="8dp"
android:src="#drawable/icon_search" />
<EditText
android:id="#+id/et_userInput"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="1"
android:background="#null"
android:hint="#string/search_friends_and_contacts"
android:singleLine="true"
android:textColor="#color/white"
android:textColorHint="#color/white"
android:textSize="14sp" />
<ImageView
android:id="#+id/icon_close"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="8dp"
android:src="#drawable/icon_close_white" />
include this in your listview Layout.
Update your Adapter class:
implements your adapter class with Filterable. And Override getFilter method and inside your getFilter method write this code:
private SearchFilter mSearchFilter ;
#Override
public Filter getFilter() {
if (mSearchFilter == null) {
mSearchFilter = new SearchFilter();
}
return mSearchFilter;
}
now create inner private class in your adapter which extends Filter:
private class SearchFilter extends Filter {
//Invoked in a worker thread to filter the data according to the constraint.
#Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults results = new FilterResults();
if (constraint != null && constraint.length() > 0) {
ArrayList<String> filterList = new ArrayList<FriendsModel>();
for (int i = 0; i < mOriginalList.size(); i++) {
if ((mOriginalList.get(i).toUpperCase())
.contains(constraint.toString().toUpperCase())) {
filterList.add(mOriginalList.get(i));
}
}
results.count = filterList.size();
results.values = filterList;
} else {
results.count = mOriginalList.size();
results.values = mOriginalList;
}
return results;
}
//Invoked in the UI thread to publish the filtering results in the user interface.
#SuppressWarnings("unchecked")
#Override
protected void publishResults(CharSequence constraint,
FilterResults results) {
mListViewArrayList = (ArrayList<String>) results.values;
notifyDataSetChanged();
}
}
also define two ArrayListVariable in your adapter class like this:
ArrayList<String> mListViewArrayList ; <----- which will be used to render data from getView Method
ArrayList<String> mOriginalList ; <----- Which holds original list all the time.
And to call this filter from activity write following code in your Activity:
et_userInput.addTextChangedListener(new TextWatcher() {
#Override
public void onTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {
yourAdapter.getFilter().filter(arg0);
}
#Override
public void beforeTextChanged(CharSequence arg0, int arg1, int arg2,
int arg3) {
}
#Override
public void afterTextChanged(Editable arg0) {
}
});
Good day,
I have a following problem. In my Android application I have a list of entries in XML that contains bus stop name and ID. Those are put in a HashMap as IDs are unique, while stop names are not. The user interface of activity contains an AutoCompleteTextView and Spinner.
My objective is to populate auto-complete view with stop names and then pass the ID of selected stop to the other class that will display bus lines on that stop in spinner (via remote API).
So what the user will do is start typing stop name (e.g. Awesome Stop) and he will see two entries in auto-complete suggestions. Depending on which one he will select spinner will show different results.
My problem is that I can't figure out how to couple AutoCompleteTextView and HashMap. Auto-complete works well with ArrayAdapter<String> populated via ArrayList<String> but it's not terribly helpful because I can only get stop name back, and it's not very helpful since I actually need ID.
Many thanks for any tip.
OK, after a fair bit of time I figured it out, thanks to the tip from joaquin. It was indeed done by implementing custom adapter. And the HashMap was not very helpful in original goal. Below is the code, if someone stumbles upon a similar challenge.
Activity:
// Members
private long currentStopId;
protected Map<String,String> lineMap;
protected ArrayList<Stop> stopMap;
protected String previousUrl = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_add_line);
// Get the list of stops from resourse XML
getStopInformation();
// Enable auto-complete
stopInput = (AutoCompleteTextView) findViewById(R.id.inputStopName);
final HashMapAdapter adapter = new HashMapAdapter(this,R.layout.stop_list,stopMap);
stopInput.setAdapter(adapter);
// Add listener for auto-complete selection
stopInput.setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view, int position, long rowId) {
String selection = (String)parent.getItemAtPosition(position);
// There we get the ID.
currentStopId = parent.getItemIdAtPosition(position);
}
});
}
Adapter implementation:
public class StopAdapter extends BaseAdapter implements Filterable {
private ArrayList<Stop> inputStopList;
private ArrayList<Stop> inputStopListClone;
private LayoutInflater lInflater;
/** Constructor */
public StopAdapter(Context context, int textViewResourceId, ArrayList<Stop> input) {
lInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inputStopList = input;
inputStopListClone = inputStopList;
}
#Override
public int getCount() {
return inputStopList.size();
}
#Override
public Object getItem(int i) {
Stop value = inputStopList.get(i);
return value.getStopName();
}
#Override
public long getItemId(int i) {
Stop stop = inputStopList.get(i);
long value = Long.parseLong(stop.getStopCode());
return value;
}
#Override
public View getView(int i, View view, ViewGroup viewGroup) {
View myView = view;
// R.layout.stop_list created in res/layout
if(myView == null)
myView = lInflater.inflate(R.layout.stop_list,viewGroup, false);
((TextView) myView.findViewById(R.id.textView)).setText(getItem(i).toString());
return myView;
}
/** Required by AutoCompleteTextView to filter suggestions. */
#Override
public Filter getFilter() {
Filter filter = new Filter() {
#Override
protected FilterResults performFiltering(CharSequence charSequence) {
FilterResults filterResults = new FilterResults();
if(charSequence == null || charSequence.length() == 0) {
ArrayList<Stop> originalValues = new ArrayList<Stop>(inputStopList);
filterResults.count = originalValues.size();
filterResults.values = originalValues;
}
else {
ArrayList<Stop> newValues = new ArrayList<Stop>();
// Note the clone - original list gets stripped
for(Stop stop : inputStopListClone)
{
String lowercase = stop.getStopName().toLowerCase();
if(lowercase.startsWith(charSequence.toString().toLowerCase()))
newValues.add(stop);
}
filterResults.count = newValues.size();
filterResults.values = newValues;
}
return filterResults;
}
#Override
protected void publishResults(CharSequence charSequence, FilterResults filterResults) {
if(filterResults != null && filterResults.count > 0) {
inputStopList = (ArrayList<Stop>)filterResults.values;
notifyDataSetChanged();
}
else notifyDataSetInvalidated();
}
};
return filter;
}
}
You are using AutoCompleteTextView instead of MultiAutoCompleteTextView.
MultiAutoCompleteTextView is exactly what you need because it works exactly equal as AutoCompleteTextView with the difference that it can show more than one suggestion (if they exist) and lets the user choose only one of them.
Reference Image: http://i.stack.imgur.com/9wMAv.png
For a nice example check out Android Developers: http://developer.android.com/reference/android/widget/MultiAutoCompleteTextView.html
More than one person have had the problem of how to implement a Filter for a ListView that uses a SimpleCursorAdapter. I had this problem and I have found lots of answers about this in this web. I have taken pieces of code from everywhere until I finally got it work and it was simpler that it looked like.
I've seen the Google I/O 2010 - The world of ListView video on youtube and it says that you have to implement getFilter method and implements Filterable on your class adapter, something like this:
public class MyListCursorAdapter extends SimpleCursorAdapter implements Filterable{
...
#Override
public Filter getFilter() {
return new Filter(){
#Override
protected FilterResults performFiltering(CharSequence charSequence){
FilterResults results = new FilterResults();
//If there's nothing to filter on, return the original data for your list
if(charSequence == null || charSequence.length() == 0){
results.values = originalData;
results.count = originalData.getCount();
}
else{
Cursor filterResultsData = null;
filterResultsData = DB.getResults(charSequence);
results.values = filterResultsData;
results.count = filterResultsData.getCount();
}
return results;
}
#Override
protected void publishResults(CharSequence charSequence, FilterResults filterResults){
filteredData = (Cursor) filterResults.values;
if (filterResults.count > 0) {
notifyDataSetChanged();
}else{
notifyDataSetInvalidated();
}
}
};
}
}
At least is what I tried to do. I've seen that using ArrayAdapter instead of Cursor, works pretty well. But in the case of Cursor it didn't work, at least not for me. Maybe I'm doing something wrong. So I was a little confused about what do to. I know that I have a edit text, a list view and everytime a put some text on my edit text I want my list get filtered.
Now I'm going to answer my own question since I want to share with you my solution.
This is What I have done:
Layout:
<EditText
android:id="#+id/editTextSearch"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="text"
android:hint="#string/search" >
</EditText>
<ListView
android:id="#id/android:list"
android:textFilterEnabled="true"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
</ListView>
Pay attention to android:textFilterEnabled="true" in ListView.
My ListActivity or ListFragment:
public class ClientesActivity extends ListFragment {
private MyListCursorAdapter myAdapter;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.activity_clientes, container, false);
//call to a method that fill my list
myListGetFilled(view);
//Put a listener to edit text search
EditText etSearch = (EditText) view.findViewById(R.id.editTextSearch);
etSearch.addTextChangedListener(new TextWatcher() {
#Override
public void onTextChanged(CharSequence cs, int arg1, int arg2, int arg3) {
// When user changed the Text
myAdapter.getFilter().filter(cs);
}
#Override
public void beforeTextChanged(CharSequence arg0, int arg1, int arg2,
int arg3) {
// TODO Auto-generated method stub
}
#Override
public void afterTextChanged(Editable arg0) {
// TODO Auto-generated method stub
}
});
return view;
}
private void myListGetFilled(View view){
Cursor mCursor = DB.fillMyList(getActivity());
if(mCursor.getCount()>0){
String[] from = new String[] { "name", "description"};
int[] to = new int[] { R.id.textViewName, R.id.textViewDescription};
ListView myListView = (ListView) view.findViewById (android.R.id.list);
myAdapter = new MyListCursorAdapter(context, R.layout.activity_row_list, mCursor, from, to);
myListView .setAdapter(myAdapter);
}
}
And finally my custom cursor adapter:
public class MyListCursorAdapter extends SimpleCursorAdapter implements Filterable{
...
/*THE METHOD THAT DOES THE MAGIC*/
public Cursor runQueryOnBackgroundThread(CharSequence constraint) {
if (getFilterQueryProvider() != null){
return getFilterQueryProvider().runQuery(constraint);
}
Cursor filterResultsData = DB.getResults(constraint);
return filterResultsData;
}
}
And that's it!!.
Hope this can be useful to anyone. And if you think there is a better solution than this one, please share!!.
I'm writing a dictionary app. My search screen is very simple: centered in the Activity is the app's logo, and aligned to the bottom of the screen is the search box. When the search box receives focus, the soft keyboard pops up and the search box moves right on top of 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"
>
<ImageView android:id="#+id/search_logo"
android:layout_width="250dp"
android:layout_height="wrap_content"
android:src="#drawable/logo_transparent"
android:layout_centerInParent="true"
android:contentDescription="#string/desc_logo"
/>
<EditText android:id="#+id/search_fld"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#drawable/textbox"
android:inputType="text"
android:hint="#string/search_hint"
android:padding="10dp"
android:layout_alignParentBottom="true"
/>
</RelativeLayout>
As soon as the user types even a single letter, I will make a query in Lucene for matching entries. I want the view on top of the search box to be a dynamically updating ListView for every letter that is typed (or deleted), but how can I do that from this XML layout? What is the right approach to this kind of design?
Following are the pointers which will eventually guide you to your answer.
Add a textwatcher to the editfield in which you are going to write the search words..
txtSearch.addTextChangedListener(textWatcher);
In afterTextChanged method of textwatcher you will need a filter with the characters typed in searchfield as parameter, to filter out the search result.
private TextWatcher textWatcher = new TextWatcher() {
#Override
public void onTextChanged(CharSequence s, int start, int before,
int count) {
// TODO Auto-generated method stub
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
// TODO Auto-generated method stub
}
#Override
public void afterTextChanged(Editable s) {
adapter.getFilter().filter(s);
adapter.notifyDataSetChanged();
}
};
Following is a class I used for filtering purpose.
/*
* Class that implements filtering functionality.
*/
public class MyFilter extends Filter {
public MyFilter(ArrayList<CustomerListRow> data) {
}
#Override
protected FilterResults performFiltering(CharSequence constraint) {
constraint = constraint.toString().toLowerCase();
FilterResults result = new FilterResults();
if (constraint != null && constraint.toString().length() > 0) {
ArrayList<CustomerListRow> filt = new ArrayList<CustomerListRow>();
for (int i = 0; i < arrayListCopy.size(); i++) {
CustomerListRow each = arrayListCopy.get(i);
if (each.getName().toLowerCase().contains(constraint)) {
filt.add(each);
}
}
result.count = filt.size();
result.values = filt;
} else {
synchronized (this) {
result.count = arrayListCopy.size();
result.values = arrayListCopy;
}
}
return result;
}
#Override
protected void publishResults(CharSequence constraint,
FilterResults results) {
ArrayList<CustomerListRow> filtered = (ArrayList<CustomerListRow>) results.values;
clear();
int size = filtered.size();
for (int i = 0; i < size; i++) {
add(filtered.get(i));
}
notifyDataSetInvalidated();
}
}
You will need to create an adapter to which you will pass your complete list, which will eventually passed to the filter.
Following is constructor of my adapter class.
public MyAdapter(Context context, int textViewResourceId,
List<CustomerListRow> objects) {
super(context, textViewResourceId, objects);
this.context = context;
inflator = (LayoutInflater) context
.getSystemService(LAYOUT_INFLATER_SERVICE);
list = (ArrayList<CustomerListRow>) objects;
filter = new MyFilter(list);
arrayListCopy.addAll(list);
}
The solution seems to be more straightforward. First, create a TextWatcher for the EditText. Then, inside onTextChanged(), this is what you do:
Create a Lucene query whenever the method is invoked. Get the results.
Call clear() in the adapter.
Add all the results to the adapter.
Call notifyDataSetChanged() on the adapter.
I have a strange problem regarding suggestion items for an AutocompleteView on Android 2.2. I am using a custom ArrayAdapter and Filter class implementation.
When I type into the AutocompleteView the suggestion drop-down pops up after entering two characters as shown in the following screenshot:
When I enter a third character the drop-down disappears:
After entering a fourth character the suggestion drop-down is displayed again:
I don't understand why the drop-down disappears when an uneven amount of characters is entered.
While debugging I noticed that getView() is called twice when an even amount of characters is entered, but ony once for an uneven amount. Might this be the reason for the faulty behavior?
Here is my source code:
public class AutoCompleteActivity extends Activity {
protected AutoCompleteTextView autoCompleteView;
protected AutoCompleteAdapter suggsAdapter;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.autocomp);
autoCompleteView = (AutoCompleteTextView) findViewById(R.id.autocomplete);
autoCompleteView.setAdapter(new AutoCompleteAdapter(this, android.R.layout.simple_dropdown_item_1line, new String[1]));
}
private class AutoCompleteAdapter extends ArrayAdapter implements Filterable {
protected LayoutInflater mInflater;
protected Filter filter;
public AutoCompleteAdapter(Context context, int textViewResourceId, String[] items) {
super(context, textViewResourceId, items);
filter = new SuggestionsFilter();
mInflater = LayoutInflater.from(context);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
if (v == null) {
v = mInflater.inflate(android.R.layout.simple_dropdown_item_1line, parent, false);
}
TextView tt = (TextView) v.findViewById(android.R.id.text1);
tt.setText("Suggestion item");
return v;
}
public Filter getFilter() {
return filter;
}
private class SuggestionsFilter extends Filter {
#Override
protected FilterResults performFiltering(CharSequence constraint) {
return null;
}
#Override
protected void publishResults(CharSequence constraint, FilterResults results) {
notifyDataSetChanged();
}
}
}
}
...and my layout file:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<!-- Pretty hint text, and maxLines -->
<AutoCompleteTextView android:id="#+id/autocomplete"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:inputType="text"
android:maxLines="1"
android:imeOptions="actionSearch"
android:layout_toLeftOf="#+id/spinner" />
I found a solution to my problem. I did not set results.count in my performFiltering method. Setting this property to e.g. results.count = 1 resolved the issue with the dissapearing suggestion items.