0

I want to implement an AutoCompleteTextView within the onQueryTextChange function of searchView, so that I get a suggestion list when I start typing in the search. How can I implement it?

@Override
public boolean onCreateOptionsMenu(Menu menu)
{
    MenuInflater menuInflater = getMenuInflater();
    menuInflater.inflate(R.menu.menu_search, menu);
    MenuItem item = menu.findItem(R.id.menu_search);

    final SearchView searchView = (SearchView)item.getActionView();

    final LayoutInflater inflater = (LayoutInflater) this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    final ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_dropdown_item_1line, buildings);
    final android.support.v7.app.ActionBar actionBar = getSupportActionBar();

    searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener()
    {
        @Override
        public boolean onQueryTextSubmit(String query)
        {
            return false;
        }

        @Override
        public boolean onQueryTextChange(String newText)
        {

            AutoCompleteTextView textView = (AutoCompleteTextView) findViewById(R.id.editText1);
            textView.setAdapter(adapter);
            adapter.getFilter().filter(newText);
            return false;
        }
    });
    return super.onCreateOptionsMenu(menu);
}
CoderPJ
  • 991
  • 6
  • 18
  • 41

2 Answers2

1

EDITED

The Layout file, named activity_search.xml.

<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/nested_parentframe"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/transparent">

    <!-- HERE IS WHERE YOUR OTHER VIEWS SHOULD GO -->

    <android.support.v7.widget.Toolbar
        android:id="@+id/nested_toolbar_1"
        android:layout_width="match_parent"
        android:layout_height="56dp"
        android:background="#ffffff" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <android.support.v7.widget.CardView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_margin="0dp"
            app:cardBackgroundColor="@android:color/transparent"
            app:cardElevation="0dp">

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:orientation="vertical"
                android:layout_margin="5dp"
                android:layout_gravity="center"
                android:background="#ffffff">

                <android.support.v7.widget.CardView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:background="#ffffff"
                    app:cardElevation="0dp"
                    app:cardPreventCornerOverlap="false">

                    <android.support.v7.widget.Toolbar
                        android:id="@+id/nested_toolbar_2"
                        android:layout_width="match_parent"
                        android:layout_height="56dp"
                        android:layout_marginTop="0dp"
                        android:layout_gravity="center" />

                </android.support.v7.widget.CardView>

            </LinearLayout>

        </android.support.v7.widget.CardView>

        <LinearLayout
            android:id="@+id/recyclerViewLayout"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_gravity="center_horizontal"
            android:layout_marginBottom="5dp"
            android:layout_marginLeft="5dp"
            android:layout_marginRight="5dp"
            android:background="#ffffff"
            android:orientation="vertical"
            android:visibility="gone">

            <android.support.v7.widget.RecyclerView
                android:id="@+id/cardsList"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:dividerHeight="1dp"/>
        </LinearLayout>

    </LinearLayout>

</FrameLayout>

Here is the Menu where SearchView is placed, named search_menu.xml.

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">

    <item
        android:id="@+id/search_menu_item"
        android:icon="@drawable/ic_search_grey"
        app:showAsAction="always|collapseActionView"
        app:actionViewClass="yourpackage.ArrayAdapterSearchView"
        android:textSize="16sp"
        android:title="Search" />
</menu>

Here is a custom ArrayAdapter for the SearchView.

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(AdapterView.OnItemClickListener listener) {
        mSearchAutoComplete.setOnItemClickListener(listener);
    }

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

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

    public void setSelection(int position){
        mSearchAutoComplete.setSelection(position);
    }

    public String getText(){
        return mSearchAutoComplete.getText().toString();
    }
}

Here is the RecyclerView list item layout, named card_item.xml.

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    card_view:cardCornerRadius="1dp">

    <TextView
        android:id="@+id/itemNametxt"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:gravity="left"
        android:text=""
        android:textStyle="normal" />

</android.support.v7.widget.CardView>

Inside your Custom Adapter write a function like this.

public class CustomAdapter extends RecyclerView.Adapter<CustomAdapter .CustomRecyclerHolder> {
    private Context context;
    private ArrayList<String> arrayList = null, stringArrayList;
    private OnItemClickListener listener;

    public CustomAdapter(Context context, ArrayList<String> items) {
        this.context = context;
        this.arrayList = items;
        this.stringArrayList = new ArrayList<String>();
        this.stringArrayList.addAll(items);
    }

    @Override
    public CustomAdapter.CustomRecyclerHolder onCreateViewHolder(ViewGroup parent, int viewType) {
         View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.card_item, parent, false);

        return new CustomRecyclerHolder(itemView);
    }

    @Override
    public void onBindViewHolder(CustomAdapter.CustomRecyclerHolder holder, int position) {
        holder.item.setText(arrayList.get(position).toString());
    }

    public class CustomRecyclerHolder extends RecyclerView.ViewHolder{
        protected TextView item;

        public CustomRecyclerHolder(View v){
            super(v);
            item = (TextView) v.findViewById(R.id.itemNametxt);

            v.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (listener != null) {
                        listener.onItemClick(item.getText().toString());
                    }
                }
            });
        }
    }

    @Override
    public int getItemCount() {
        return this.arrayList.size();
    }

    public void filter(String filterString) {
        filterString = filterString.toLowerCase(Locale.getDefault());
        arrayList.clear();//Your list of items
        if(filterString.length() == 0) {
            arrayList.addAll(stringArrayList);
            //stringArrayList - 2nd list of items
        }
        else {
            for(String item : stringArrayList){
                if(item.toLowerCase(Locale.getDefault()).contains(filterString)) {
                    arrayList.add(item );
                }
            }
        }
        notifyDataSetChanged();
    }

    public void setOnItemClickListener(OnItemClickListener listener){
        this.listener = listener;
    }

    public interface OnItemClickListener{
        public void onItemClick(String item);
    }
}

Finally the Activity. EDITED

public class ExampleActivity extends AppCompatActivity {

    private ArrayAdapterSearchView searchView;
    private LinearLayout recycleLayout;
    private ArrayList<String> stringList;
    private RecyclerView recyclerView;
    private CustomAdapter adapter;
    private Toolbar mToolbar1, mToolbar2;
    private FrameLayout frameLayout;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_search);

        mToolbar1 = (Toolbar) findViewById(R.id.nested_toolbar_1);
        mToolbar2 = (Toolbar) findViewById(R.id.nested_toolbar_2);

        frameLayout = (FrameLayout) findViewById(R.id.nested_parentframe);

        setSupportActionBar(mToolbar2);
        getSupportActionBar().setTitle("Search");
        mToolbar1.setNavigationIcon(R.mipmap.ic_action_overflow);

        mToolbar2.setTitleTextColor(getResources().getColor(android.R.color.tertiary_text_light));

        recycleLayout = (LinearLayout) findViewById(R.id.recyclerViewLayout);

        recyclerView = (RecyclerView) findViewById(R.id.cardsList);
        recyclerView.setHasFixedSize(true);
        LinearLayoutManager llm = new LinearLayoutManager(this);
        llm.setOrientation(LinearLayoutManager.VERTICAL);
        recyclerView.setLayoutManager(llm);

        getSupportActionBar().setDisplayShowHomeEnabled(true);

        String[] strArray = new String[]{"Item One", "Item Two", "Item Three", "Item Four", "Item Five"};
        //This is your String array
        for(int i = 0; i < strArray.length; i++){
            stringList.add(strArray[i]);
        }

        if(!stringList.isEmpty()){
            adapter = new CustomAdapter(this, stringList);
            recyclerView.setAdapter(adapter);

            recycleLayout.setVisibility(View.VISIBLE);

            adapter.setOnItemClickListener(new CustomAdapter.OnItemClickListener() {
                @Override
                public void onItemClick(String item) {
                    searchView.setQuery(item, false);
                }
            });
        }
        else{
            recycleLayout.setVisibility(View.GONE);
        }       

    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.search_menu, menu);

        MenuItem searchItem = menu.findItem(R.id.search_menu_item);

        searchView = (ArrayAdapterSearchView) MenuItemCompat.getActionView(searchItem);
        searchView.setLayoutParams(new ActionBar.LayoutParams(Gravity.LEFT));

        searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
            @Override
            public boolean onQueryTextSubmit(String query) {
                return false;
            }

            @Override
            public boolean onQueryTextChange(String query) {
                if (query.length() != 0) {
                    if (null != adapter) {
                        adapter.filter(query.toString());//This will filter the RecyclerView
                        recyclerView.setVisibility(View.VISIBLE);
                    }
                }
                else{
                    recyclerView.setVisibility(View.GONE);
                }
                return false;
            }
        });

        searchView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String length = searchView.getText();
                searchView.setSelection(length.length());
            }
        });

        return true;
    }

}
vidulaJ
  • 1,232
  • 1
  • 16
  • 31
  • Can you please give me the entire code? As in from Main Activity.java and the layout files? It would be very helpful – CoderPJ Oct 25 '16 at 06:37
  • Just to let you know, I am not using any listView for searching the items. I've created a string array in the MainActivity.java – CoderPJ Oct 25 '16 at 06:46
  • I have provided the code for searching through a ListView. I can give you a full code if you like. But ss per your last comment, what I understood is you don't want a ListView, but an AutoComplete Adapter to set to the ActionBat Menu. – vidulaJ Oct 25 '16 at 06:54
  • Yes I want an AutoComplete adapter. Can you please provide me with the full code for that? – CoderPJ Oct 25 '16 at 07:08
  • I suggest you to follow this example. http://stackoverflow.com/questions/15804805/android-action-bar-searchview-as-autocomplete – vidulaJ Oct 25 '16 at 07:36
  • Thank you! But I am specifically looking at creating a Search Bar with autoComplete feature in it. I've already created something similar to what you've suggested. It has an autoCompleteTextView in it, which is not what I want. I hope you understand what I mean. Please suggest me a solution – CoderPJ Oct 25 '16 at 22:52
  • Sure. I have this workaround which SearchView acts as an AutoCompleteTextView but it uses a RecyclerView to display the suggestions. I could provide you that I you like. – vidulaJ Oct 26 '16 at 04:07
  • Sure. That would be really helpful. Please do provide me with the entire code – CoderPJ Oct 26 '16 at 07:32
  • And also, just to let you know, I am not using a ListView. I've declared a string array in my MainActivity.java. – CoderPJ Oct 26 '16 at 07:40
  • No problem. You can use a String array for populating the ListView. – vidulaJ Oct 26 '16 at 08:01
  • Oh okay. I will go through it. Please send the code – CoderPJ Oct 26 '16 at 09:36
  • I have edited the answer and let me know whether it is working or not. – vidulaJ Oct 26 '16 at 12:11
  • changed PlaceRecyclerHolder to CustomRecyclerHolder. There are a lot of errors in the code. There is an error in the CustomAdaper constructor. The error says, there is no default constructor in 'android.widget.ArrayAdapter'. I tried various things, but Array adapter constructor doesn't take object:List as it's second parameter. Please help me out here – CoderPJ Oct 26 '16 at 21:05
  • That is because I have customized it by taking it from a working app. I'll correct it. – vidulaJ Oct 27 '16 at 03:36
  • Edited. Please have a look. – vidulaJ Oct 27 '16 at 03:42
  • Attempt to invoke virtual method 'void com.example.mypc.samplesearch.ArrayAdapterSearchView.setLayoutParams(android.view.ViewGroup$LayoutParams)' on a null object reference. Can you please resolve this is error? – CoderPJ Oct 27 '16 at 05:11
  • Sure .......java.lang.NullPointerException: Attempt to invoke virtual method 'void com.example.pc.samplesearch.ArrayAdapterSearchView.setLayoutParams(android.view.ViewGroup$LayoutParams)' on a null object reference at com.example.pc.samplesearch.MainActivity.onCreateOptionsMenu(MainActivity.java:81) searchView.setLayoutParams(new ActionBar.LayoutParams(Gravity.LEFT)); – CoderPJ Oct 27 '16 at 07:47
  • Did you find the problem? – CoderPJ Oct 28 '16 at 01:46
  • Have you stated your SearchView inside the menu like this? app:actionViewClass="com.example.pc.samplesearch.ArrayAdapterSearchView" – vidulaJ Oct 28 '16 at 03:18
  • It is working fine now. Thank you so much. I have a few more questions. How do I make the drop down suggestion list better? In the sense, larger text size? Also, why does the suggestion list appear on application startup? What's the code to disable the list appearing on startup? – CoderPJ Oct 28 '16 at 04:43
  • You have to control the visibility of the drop down list via "recycleLayout" variable. When the Text Change Listener is working and only if matches are found you have to show the drop down list and otherwise hide it. – vidulaJ Oct 28 '16 at 04:49
  • Got it. Also, can I make the suggestion list clickable? As in, when I click on Item two, the string should get populated on the search field – CoderPJ Oct 28 '16 at 05:03
  • I think it happens already, doesn't it? Thanks for the acceptance! searchView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { String length = searchView.getText(); searchView.setSelection(length.length()); } }); – vidulaJ Oct 28 '16 at 05:10
  • I tried it. Technically speaking, it should work. It isn't working. – CoderPJ Oct 28 '16 at 05:19
  • Could you look into the issue? – CoderPJ Oct 28 '16 at 05:31
  • Sure. Could you hold on for a second? Um working on it. – vidulaJ Oct 28 '16 at 05:32
  • See the EDITED content inside "ExampleActivity". That will do. – vidulaJ Oct 28 '16 at 06:01
  • Thank you! Works perfect now. Also, I have an image to add to the background. How do I fit it perfectly under the search bar? A part of the image is covered by the search bar – CoderPJ Oct 28 '16 at 06:19
  • @vidulaJ ..can you help me out here --> https://stackoverflow.com/questions/59532667/particular-titlefetched-from-api-using-searchview – Wini Jan 04 '20 at 16:05
-1

I suggest you to use Material SearchView.

http://joerichard.net/android/android-material-design-searchview-example/

MaterialSearchView searchView = (MaterialSearchView) findViewById(R.id.search_view);
    searchView.setOnQueryTextListener(new MaterialSearchView.OnQueryTextListener() {
            @Override
            public boolean onQueryTextSubmit(String query) {
                //Do some magic
                return false;
            }

            @Override
            public boolean onQueryTextChange(String newText) {
                //Do some magic
                return false;
            }
        });

        searchView.setOnSearchViewListener(new MaterialSearchView.SearchViewListener() {
            @Override
            public void onSearchViewShown() {
                //Do some magic
            }

            @Override
            public void onSearchViewClosed() {
                //Do some magic
            }
        });

OUTPUT

enter image description here

Aditya Vyas-Lakhan
  • 13,409
  • 16
  • 61
  • 96
  • Please check the question. He is asking for "How to implement AutoCompleteTextView within onQueryTextChange function of SearchView in actionbar" and not just SearchVIew – Aniket Nov 30 '18 at 09:55