43

I am using a SearchView in the Action Bar. I want to use autocomplete feature on the search view to get results from the database.

Is this possible? Or do I need to use a custom text box and then add autocomplete to that?

Jonik
  • 80,077
  • 70
  • 264
  • 372
Harsha M V
  • 54,075
  • 125
  • 354
  • 529

7 Answers7

41

So I just had to do this for the v7 version and was dismayed to find that I cannot simply set the adapter with an ArrayAdapter.

I did not want to use a stock AutoCompleteTextView (as the top commenter here does), because then you're missing out on a number of snazzy features of SearchView, like the little search icon and x button.

So I extended SearchView and got this:

public class ArrayAdapterSearchView extends SearchView {

private SearchView.SearchAutoComplete mSearchAutoComplete;

public ArrayAdapterSearchView(Context context) {
    super(context);
    initialize();
}

public ArrayAdapterSearchView(Context context, AttributeSet attrs) {
    super(context, attrs);
    initialize();
}

public void initialize() {
    mSearchAutoComplete = (SearchAutoComplete) findViewById(android.support.v7.appcompat.R.id.search_src_text);
    this.setAdapter(null);
    this.setOnItemClickListener(null);
}

@Override
public void setSuggestionsAdapter(CursorAdapter adapter) {
    // don't let anyone touch this
}

public void setOnItemClickListener(OnItemClickListener listener) {
    mSearchAutoComplete.setOnItemClickListener(listener);
}

public void setAdapter(ArrayAdapter<?> adapter) {
    mSearchAutoComplete.setAdapter(adapter);
}

public void setText(String text) {
    mSearchAutoComplete.setText(text);
}

}

You can use this in your menu xml for the ActionBar like so:

<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto" >

<item
    android:id="@+id/action_search"
    android:icon="@android:drawable/ic_menu_add"
    android:title="TITLE"
    app:actionViewClass="com.yourpackage.ArrayAdapterSearchView"
    app:showAsAction="ifRoom|collapseActionView"/>

</menu>

You may also want to add click functionality to the autocomplete list (for example, setting the text to the EditText):

MenuItem searchItem = menu.findItem(R.id.action_search);
final ArrayAdapterSearchView searchView = (ArrayAdapterSearchView)searchItem.getActionView();
searchView.setOnItemClickListener(new OnItemClickListener() {
    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {

        searchView.setText(adapter.getItem(position).toString());

    }
});

And here is a similar version for the regular old android.widget.SearchView:

public class ArrayAdapterSearchView extends SearchView {

private AutoCompleteTextView mSearchAutoComplete;

public ArrayAdapterSearchView(Context context) {
    super(context);
    initialize();
}

public ArrayAdapterSearchView(Context context, AttributeSet attrs) {
    super(context, attrs);
    initialize();
}

public void initialize() {
    mSearchAutoComplete = (AutoCompleteTextView) findViewById(getResources().getIdentifier("android:id/search_src_text", null, null));
    setAutoCompleSuggestionsAdapter(null);
    setOnItemClickListener(null);
}

@Override
public void setSuggestionsAdapter(CursorAdapter adapter) {
    throw new UnsupportedOperationException("Please use setAutoCompleSuggestionsAdapter(ArrayAdapter<?> adapter) instead");
}

public void setOnItemClickListener(AdapterView.OnItemClickListener listener) {
    mSearchAutoComplete.setOnItemClickListener(listener);
}

public void setAutoCompleSuggestionsAdapter(ArrayAdapter<?> adapter) {
    mSearchAutoComplete.setAdapter(adapter);
}

public void setText(String text) {
    mSearchAutoComplete.setText(text);
}

}
Prateek Gupta
  • 835
  • 10
  • 18
  • I liked this idea and implemented it, but I got a problem. I can see my autocomplete results but when I click on an item, the item string doesn't get selected. I mean it doesn't show up in the textView once I selected it. Can you provide more insight into this ? Or working code snippet ? – shaktiman_droid Dec 09 '13 at 17:39
  • Then I'll have to add a new method (setText) in my customSearchView class. – shaktiman_droid Dec 09 '13 at 18:07
  • Yeah: public void setText(String text) { mSearchAutoComplete.setText(text); } –  Dec 09 '13 at 21:30
  • Why not use the default suggestions feature? like here: http://developer.android.com/guide/topics/search/adding-custom-suggestions.html – Vedant Agarwala Apr 28 '15 at 10:59
  • Thanks; I'm using this approach in conjunction with `onQueryTextChange()` (`SearchView.OnQueryTextListener`) and got things working quite quickly. – Jonik Apr 28 '15 at 13:39
  • 1
    @vedant1811 May be because ppl don't wanna use `CursorAdapter`. – Mussa Sep 05 '15 at 06:35
  • @Alexandr , I am new in android and i applied your code but i have a list of strings and searchview element , how to set adapter to searchview and fill the result list from my Strings list? – Asmaa Rashad Jun 09 '16 at 11:38
  • @AsmaaRashad, use setAdapter method of ArrayAdapterSearchView searchView. How to create adapter from strings array you can find here - http://stackoverflow.com/a/12109813/2308720 – Oleksandr Jun 09 '16 at 12:46
36

I have use custom AutoCompleteTextView and add it in ActionBar.

enter image description here

public class MainActivity extends Activity {

    private static final String[] COUNTRIES = new String[] { "Belgium",
            "France", "France_", "Italy", "Germany", "Spain" };

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ActionBar actionBar = getActionBar();
        actionBar.setDisplayHomeAsUpEnabled(true);
        actionBar.setDisplayShowCustomEnabled(true);
        // actionBar.setDisplayShowTitleEnabled(false);
        // actionBar.setIcon(R.drawable.ic_action_search);

        LayoutInflater inflator = (LayoutInflater) this
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        View v = inflator.inflate(R.layout.actionbar, null);

        actionBar.setCustomView(v);

        ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
                android.R.layout.simple_dropdown_item_1line, COUNTRIES);
        AutoCompleteTextView textView = (AutoCompleteTextView) v
                .findViewById(R.id.editText1);
        textView.setAdapter(adapter);

    }

}

and Your Layout:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:gravity="center" >

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Action Bar:"
        android:textAppearance="?android:attr/textAppearanceMedium"
        android:textColor="#FFFFFF" />

    <AutoCompleteTextView
        android:id="@+id/editText1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:ems="10"
        android:imeOptions="actionSearch"
        android:inputType="textAutoComplete|textAutoCorrect"
        android:textColor="#FFFFFF" >

        <requestFocus />
    </AutoCompleteTextView>

</LinearLayout>

Edited:

Please check this and this link it may help you. code is here.

Community
  • 1
  • 1
Dhaval Parmar
  • 18,812
  • 8
  • 82
  • 177
  • how can i add the data source as a DATABASE ? with the limited string its easier. but i have close to 250 and one more list with upto 4000 rows – Harsha M V Apr 08 '13 at 11:24
  • 3
    Ok but this is not a SearchView. I actually want a Search icon at the left and X icon at the right when the text is there. – tasomaniac Jul 18 '13 at 15:16
  • @tasomaniac: which you want is also not a search view... whatever combine above code and this code ----> http://stackoverflow.com/a/6355178/1168654 – Dhaval Parmar Jul 19 '13 at 05:26
  • 4
    I solved my problem. Actually the SearchView has built-in autocomplete feature but it needs a contentprovider. Instead of setting AutoCompleteTextView and its necessary functions, I simply create a ContentProvider that only does query not insert, delete. And it is solved. – tasomaniac Jul 19 '13 at 09:09
  • Is it possible to add two search widget in the same action bar of an activity ? – Elyes Jlassi Oct 30 '14 at 16:47
  • Where's actionbar? – Rasshu Jul 07 '16 at 14:29
8

Here's an alternative method using CursorAdapter:

ExampleActivity.java

private Menu menu;

@Override
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public boolean onCreateOptionsMenu(Menu menu) {

    getMenuInflater().inflate(R.menu.example, menu);

    this.menu = menu;

    if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {

        SearchManager manager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);

        SearchView search = (SearchView) menu.findItem(R.id.search).getActionView();

        search.setSearchableInfo(manager.getSearchableInfo(getComponentName()));

        search.setOnQueryTextListener(new OnQueryTextListener() { 

            @Override 
            public boolean onQueryTextChange(String query) {

                loadHistory(query);

                return true; 

            } 

        });

    }

    return true;

}

// History
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
private void loadHistory(String query) {

    if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {

        Cursor cursor = db.rawQuery("SELECT * FROM items", null); // Example database query

        SearchManager manager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);

        final SearchView search = (SearchView) menu.findItem(R.id.search).getActionView();

        search.setSearchableInfo(manager.getSearchableInfo(getComponentName()));

        search.setSuggestionsAdapter(new ExampleAdapter(this, cursor, items));

    }

}

Now you need to create an adapter extended from CursorAdapter:

ExampleAdapter.java

public class ExampleAdapter extends CursorAdapter {

    private List<String> items;

    private TextView text;

    public ExampleAdapter(Context context, Cursor cursor, List<String> items) {

        super(context, cursor, false);

        this.items = items;

    }

    @Override
    public void bindView(View view, Context context, Cursor cursor) {

        text.setText(cursor.getString(cursor.getColumnIndex("text"))); // Example column index

    }

    @Override
    public View newView(Context context, Cursor cursor, ViewGroup parent) {

        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

        View view = inflater.inflate(R.layout.item, parent, false);

        text = (TextView) view.findViewById(R.id.text);

        return view;

    }

}

Please note: when you import CursorAdapter don't import the Android support version, import the standard android.widget.CursorAdapter instead.

The adapter will also require a custom layout:

res/layout/item.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">

    <TextView
        android:id="@+id/item"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</RelativeLayout>

You can now customize list items by adding additional text or image views to the layout and populating them with data in the adapter. Now you need a SearchView menu item:

res/menu/example.xml

<menu xmlns:android="http://schemas.android.com/apk/res/android">

    <item
        android:id="@+id/search"
        android:title="@string/search"
        android:showAsAction="ifRoom"
        android:actionViewClass="android.widget.SearchView" />

</menu>

Then create a searchable configuration:

res/xml/searchable.xml

<searchable xmlns:android="http://schemas.android.com/apk/res/android"
    android:label="@string/search"
    android:hint="@string/search" >
</searchable>

Finally add this inside the relevant activity tag in the manifest file:

AndroidManifest.xml

<intent-filter>
    <action android:name="android.intent.action.SEARCH" />
</intent-filter>

<meta-data
    android:name="android.app.default_searchable"
    android:value="com.example.ExampleActivity" />
<meta-data
    android:name="android.app.searchable"
    android:resource="@xml/searchable" />

Please note: The @string/search string used in the examples should be defined in values/strings.xml, also don't forget to update the reference to com.example for your project.

Here's the original tutorial for reference:

http://tpbapp.com/android-development/android-action-bar-searchview-tutorial

tpbapp
  • 2,506
  • 2
  • 19
  • 21
  • THANKS !!! made my day :) One change for me, I'm gonna get the data by asking a server for it and then update the SearchView with a new adapter. Will lett you know if it works. Thanks again ! – Shirane85 May 20 '14 at 13:00
  • @Shirane85 Hey no problem, hope it goes well. This method it seems to me is designed for displaying results from a database due to the required Cursor data format which is the standard format for handling database data. I have adapted it here also for use with an ArrayList in order to be generally more compatible with a typical data set, however this will of course limit performance especially when working with large amounts of data. – tpbapp May 20 '14 at 16:23
  • Well, i have a problem after all. When calling the network after filling a letter in the search box i return true in onQueryTextChange. Until now its good and nothing happen. But when the response call back and i perform search.setSuggestionsAdapter() still nothing happen and the suggestion popup does not displayed. The weird thing is that after filling a second letter, it shows suggestion of the first adapter immediately. Help is needed... – Shirane85 May 22 '14 at 08:27
  • @Shirane85 does that happen for example when you create a static example list instead of loading from a web resource? It sounds like you will need to make this into another question and post your code, as this does not happen for me. If you do post a question, please link from here and I will try to help. – tpbapp May 22 '14 at 12:51
  • The code is bugged. If it's used as it is, it shows strange (or rather old) suggestions. The solution is to create and set a new adapter every time and **always call notifyDataSetChanged**. – 0101100101 Jul 22 '15 at 14:26
  • Link to the original tutorial for reference: *is Dead* – Kenny Dabiri Nov 28 '19 at 16:23
8

I was also facing this issue for the auto complete search view and fix it without using any extra layout and auto complete text view, there is a class called SearchAutoComplete. I used this to achieve the auto complete feature, just put a simple list adapter which contain a ArrayList of items to suggest with search view. Set the adapter to your SearchAutoComplete and auto complete feature will work below is my code. Remember you don't have to add any custom layout. Just replace your onCreateOptionsMenu(...) method with mine code:

    @Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);

MenuItem searchItem = menu.findItem(R.id.search);
SearchView mSearchView = (SearchView) MenuItemCompat.getActionView(searchItem);

SearchAutoComplete searchAutoComplete = (SearchAutoComplete)     mSearchView.findViewById(android.support.v7.appcompat.R.id.search_src_text);

ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
android.R.layout.simple_dropdown_item_1line, itemArrayList);
searchAutoComplete.setAdapter(adapter);

SearchManager searchManager =
(SearchManager) getSystemService(this.SEARCH_SERVICE);
mSearchView.setSearchableInfo(
searchManager.getSearchableInfo(getComponentName()));
return true;
}

Clicking the suggested item the item should appear on the search view so add the below code just after you set your adapter to searchAutoComplete inside the onCreateOptionmenu(...) method

  searchAutoComplete.setOnItemClickListener(new OnItemClickListener() {

    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position,
    long id) {
    // TODO Auto-generated method stub

    String searchString=(String)parent.getItemAtPosition(position);
    searchAutoComplete.setText(""+searchString);
    Toast.makeText(MainActivity.this, "you clicked "+searchString, Toast.LENGTH_LONG).show();

    }
    });
HAXM
  • 3,578
  • 4
  • 31
  • 38
  • I tried this, but got this exception: `java.lang.NullPointerException: Attempt to invoke virtual method 'void android.support.v7.widget.SearchView$SearchAutoComplete.setTextColor(int)' on a null object reference`. It appears the searchAutoComplete always returns null for me. Any idea why this is? – VIN Apr 11 '16 at 04:06
  • Hi @HAXM... this worked for me... but I am getting the suggestions list in a grayish background, how to get that in a white background? – SoulRayder Jan 07 '17 at 19:16
  • @SoulRayder , change the theme of your toolbar, if you are not using toolbar, then use toolbar, cause without using toolbar you have to change the theme of your activity, that will change the appearance of activity – HAXM Jan 07 '17 at 20:49
6

Yes it is possible. Build a table (such as in an SQLiteDatabase) for your suggestions and format the table with required columns.

See this link

Arun C
  • 9,035
  • 2
  • 28
  • 42
  • is it possible to add the autocomplete instead ? – Harsha M V Apr 04 '13 at 08:12
  • [See this](http://stackoverflow.com/questions/11491515/turn-autocompletetextview-into-a-searchview-in-actionbar-instead) It gives an explanation as of how to implement auto-complete for search view. – buggydroid Apr 15 '13 at 09:50
3
    SearchAutoComplete searchAutoComplete = mSearchView.findViewById(androidx.appcompat.R.id.search_src_text);

for androidx version

Akgun Studio
  • 166
  • 1
  • 7
1

You can do this with a CursorAdapter via something like:

MenuItem searchItem = menu.findItem(R.id.action_search);
SearchView searchView = (SearchView) MenuItemCompat.getActionView(searchItem);

searchView.setSuggestionsAdapter(adapter);