Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I create a "Search" field in a contextual action bar?

I have an activity with an ActionBar. One of the options is to search a document (not necessarily local). I want to use a contextual action bar (CAB) with the following items:

  • edit field - place for user to enter text they want to search for
  • Previous Button - moves to the previous item that matches the search
  • Next Button - moves to the next item that matches the search

I want to use a CAB for several reasons. Primarily, I want the user to pick an option which will bring up the CAB defined above. When the user is done with the search, they select the done button and the ActionBar returns to previous state.

Here's the problem. I can't get the search item to appear in my CAB in an expanded state. NOTE: The activity I'm attempting to modify is NOT the main activity but is an activity launched by the user based on certain events. Once this activity is loaded, the user may or may not decide to use the 'search' functionality I'm describing. I also do not want Android to do the searching. I have an API that will search for the results I want and allow me to navigate to the prev/next search result.

My code for the CAB (which is being called correctly) is:

     protected ActionMode mActionModeSearch;
private ActionMode.Callback mActionModeSearchCallback = new ActionMode.Callback()
{
    @Override
    public boolean onCreateActionMode(ActionMode actionMode, Menu menu)
    {
        actionMode.getMenuInflater().inflate(R.menu.pdf_menu_search, menu);
        // Associate searchable configuration with the SearchView
        SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
        SearchView searchView = (SearchView) menu.findItem(R.id.pdf_menu_search_item).getActionView();
        searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));
        searchView.setIconifiedByDefault(false);
        searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener()
        {
            @Override
            public boolean onQueryTextSubmit(String s)
            {
                return false;
            }

            @Override
            public boolean onQueryTextChange(String s)
            {
                return false;
            }
        });
        return true;
    }

    @Override
    public boolean onPrepareActionMode(ActionMode actionMode, Menu menu)
    {
        return false;
    }

    @Override
    public boolean onActionItemClicked(ActionMode actionMode, MenuItem menuItem)
    {
        switch(menuItem.getItemId())
        {
            case R.id.pdf_menu_search_prev:
                findPrevSearchResult();
                return true;
            case R.id.pdf_menu_search_next:
                findNextSearchResult();
                return true;
            default:
                return false;
        }
    }

    @Override
    public void onDestroyActionMode(ActionMode actionMode)
    {
        //resetHideToolbarsTimer();
    }
};

The CAB menu code is:

 <?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">
<group android:id="@+id/group_search_mode">
    <item
        android:id="@+id/pdf_menu_search_item"
        android:title="@string/search"
        android:icon="@drawable/ic_pdf_action_search"
        app:showAsAction="collapseActionView|ifRoom"
        app:actionViewClass="android.support.v7.widget.SearchView"/>
    <item
        android:id="@+id/pdf_menu_search_prev"
        android:title="@string/search_prev"
        android:icon="@drawable/ic_pdf_action_search_prev"
        app:showAsAction="ifRoom" />
    <item
        android:id="@+id/pdf_menu_search_next"
        android:title="@string/search_next"
        android:icon="@drawable/ic_pdf_action_search_next"
        app:showAsAction="ifRoom" />
</group>

I also changed my activity definition in AndroidManifest.xml although I'm not sure this is required:

         <activity
        android:name="com.myapp.myActivity"
        android:label="@string/app_name">
        <intent-filter>
            <action android:name="android.intent.action.SEARCH" />
        </intent-filter>
        <meta-data
            android:name="android.app.default_searchable"
            android:value="com.myapp.myActivity" />
        <meta-data
            android:name="android.app.searchable"
            android:resource="@xml/searchable" />
    </activity>

When I run the app, the activity load correctly. When the user selects the search option, I load the CAB and it seems to be running fine. I've stepped through the code to make sure the onCreateActionMode is functioning as expected. But, all I see is the icon for search, next and previous, with the 'Done' button. When I touch the 'Search' icon, it doesn't do anything. No text field is created in the CAB for me to enter text. What am I doing wrong????

Screenshot showing the CAB coming up. As you can see, the search icon shows but doesn't do anything when I press it. What I really need is for the search edit box to appear by default.

enter image description here

like image 877
JustLearningAgain Avatar asked Oct 16 '14 23:10

JustLearningAgain


2 Answers

First, we should set always value for app:showAsAction of all menu items:

<?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">
    <group android:id="@+id/group_search_mode">
        <item
            android:id="@+id/pdf_menu_search_item"
            android:icon="@drawable/ic_pdf_action_search"
            android:title="@string/search"
            app:actionViewClass="android.support.v7.widget.SearchView"
            app:showAsAction="always"/>
        <item
            android:id="@+id/pdf_menu_search_prev"
            android:icon="@drawable/ic_pdf_action_search_prev"
            android:title="@string/search_prev"
            app:showAsAction="always"/>
        <item
            android:id="@+id/pdf_menu_search_next"
            android:icon="@drawable/ic_pdf_action_search_next"
            android:title="@string/search_next"
            app:showAsAction="always"/>
    </group>
</menu>

Secondary, in this case we don't need to set intent filter for our Activity and searchable info for our SearchView.

Definition of this Activity in AndroidManifest.xml:

<activity
    android:name="com.myapp.myActivity"
    android:label="@string/app_name" />

ActionMode.Callback implementation:

private ActionMode.Callback mActionModeSearchCallback = new ActionMode.Callback() {

    private SearchView mSearchView;

    @Override
    public boolean onCreateActionMode(ActionMode actionMode, Menu menu) {
        actionMode.getMenuInflater().inflate(R.menu.home, menu);
        mSearchView = (SearchView) MenuItemCompat.getActionView(menu.findItem(R.id.pdf_menu_search_item));
        mSearchView.setIconifiedByDefault(false);
        mSearchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
            @Override
            public boolean onQueryTextSubmit(String s) {
                return false;
            }

            @Override
            public boolean onQueryTextChange(String s) {
                return false;
            }
        });
        return true;
    }

    @Override
    public boolean onPrepareActionMode(ActionMode actionMode, Menu menu) {
        mSearchView.requestFocus();
        return true;
    }

    @Override
    public boolean onActionItemClicked(ActionMode actionMode, MenuItem menuItem) {
        switch (menuItem.getItemId()) {
            case R.id.pdf_menu_search_prev:
                findPrevSearchResult();
                return true;
            case R.id.pdf_menu_search_next:
                findNextSearchResult();
                return true;
            default:
                return false;
        }
    }

    @Override
    public void onDestroyActionMode(ActionMode actionMode) {

    }
};

I just tried this code on three 4.0+ devices and it was fully working. But I didn't test on devises with lower OS versions.

Hope it will be helpful for you.

like image 169
erakitin Avatar answered Oct 13 '22 11:10

erakitin


i have problem searchView in CAB so i set layout(with edittext) in manu item, it give me same view as searchview try this i hope it works for you

menu/search.xml

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

    <item
        android:id="@+id/edt_mySearch"
        android:actionLayout="@layout/search_bar"
        android:enabled="true"
        android:showAsAction="always"
        android:visible="true"/>

</menu>

layout/search _bar.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="fill_parent"
    >


    <EditText 
        android:layout_alignParentLeft="true"
        android:id="@+id/edt_search"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:hint=" Search..."
        />


</RelativeLayout>

and myAction mode

mActionModeCallback = new ActionMode.Callback() {

            @Override
            public boolean onCreateActionMode(ActionMode mode, Menu menu) {
                // mode.setTitle("Demo");
                getSupportMenuInflater().inflate(R.menu.search, menu);
                RelativeLayout m = (RelativeLayout) menu.findItem(
                        R.id.edt_mySearch).getActionView();
                EditText mSearchView = (EditText) m
                        .findViewById(R.id.edt_search);

                mSearchView.addTextChangedListener(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) {

                    }

                    @Override
                    public void afterTextChanged(Editable s) {
                        // search here
                    }
                });
                return true;
            }

            @Override
            public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
                // TODO Auto-generated method stub
                return false;
            }

            @Override
            public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
                return false;
            }

            @Override
            public void onDestroyActionMode(ActionMode mode) {
            }

        };
like image 43
Lokesh Avatar answered Oct 13 '22 12:10

Lokesh