Cómo configurar una interfaz de búsqueda

A partir de Android 3.0, el widget SearchView como elemento en la barra de la app es la manera preferida de proporcionar la opción de búsqueda en tu app. Al igual que con todos los elementos de la barra de la app, puedes configurar el elemento SearchView para que se muestre en todo momento, solo cuando haya espacio o como una acción contraíble, que inicialmente muestra SearchView como ícono y luego usa toda la barra de la app como campo de búsqueda cuando el usuario hace clic en él.

Nota: Más adelante en esta clase, obtendrás información sobre cómo hacer que tu app admita hasta Android 2.1 (API nivel 7) para dispositivos que no son compatibles con SearchView.

Cómo agregar la vista de búsqueda a la barra de apps

Para agregar un widget SearchView a la barra de la app, crea un archivo llamado res/menu/options_menu.xml en tu proyecto y agrega el siguiente código al archivo. Este código define cómo se crea el elemento de búsqueda, por ejemplo, el ícono que se usará y el título del elemento. El atributo collapseActionView permite que tu SearchView se expanda para ocupar toda la barra de la app y se contraiga en un elemento normal de la barra de la app cuando no esté en uso. Debido al espacio limitado de la barra de apps en teléfonos celulares, se recomienda el uso del atributo collapsibleActionView a fin de brindar una mejor experiencia del usuario.

    <?xml version="1.0" encoding="utf-8"?>
    <menu xmlns:android="http://schemas.android.com/apk/res/android">
        <item android:id="@+id/search"
              android:title="@string/search_title"
              android:icon="@drawable/ic_search"
              android:showAsAction="collapseActionView|ifRoom"
              android:actionViewClass="android.widget.SearchView" />
    </menu>
    

Nota: Si ya tienes un archivo XML existente para los elementos del menú, puedes agregar el elemento <item> a ese archivo.

Para mostrar SearchView en la barra de la app, infla el recurso del menú XML (res/menu/options_menu.xml) en el método onCreateOptionsMenu() de tu actividad:

Kotlin

    override fun onCreateOptionsMenu(menu: Menu): Boolean {
        menuInflater.inflate(R.menu.options_menu, menu)

        return true
    }
    

Java

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.options_menu, menu);

        return true;
    }
    

Si ejecutas tu app ahora, SearchView aparecerá en la barra de la app, pero no funcionará. A continuación, tienes que definir cómo se comporta SearchView.

Cómo crear una configuración que permite búsquedas

Una configuración que permite búsquedas define cómo se comporta SearchView y se define en un archivo res/xml/searchable.xml. Como mínimo, debe contener un atributo android:label que tenga el mismo valor que el atributo android:label de <application> o <activity> en tu manifiesto de Android. Sin embargo, también se recomienda agregar un atributo android:hint a fin de que el usuario tenga una idea de lo que se ingresa en el cuadro de búsqueda:

    <?xml version="1.0" encoding="utf-8"?>

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

En el archivo de manifiesto de tu aplicación, declara un elemento <meta-data> que apunte al archivo res/xml/searchable.xml de manera que tu app sepa dónde encontrarlo. Declara el elemento en un objeto <activity> en el que deseas mostrar el elemento SearchView:

    <activity ... >
        ...
        <meta-data android:name="android.app.searchable"
                android:resource="@xml/searchable" />

    </activity>
    

En el método onCreateOptionsMenu() que creaste antes, asocia la configuración que se puede buscar con SearchView mediante una llamada a setSearchableInfo(SearchableInfo):

Kotlin

    override fun onCreateOptionsMenu(menu: Menu): Boolean {
        menuInflater.inflate(R.menu.options_menu, menu)

        // Associate searchable configuration with the SearchView
        val searchManager = getSystemService(Context.SEARCH_SERVICE) as SearchManager
        (menu.findItem(R.id.search).actionView as SearchView).apply {
            setSearchableInfo(searchManager.getSearchableInfo(componentName))
        }

        return true
    }
    

Java

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.options_menu, menu);

        // Associate searchable configuration with the SearchView
        SearchManager searchManager =
               (SearchManager) getSystemService(Context.SEARCH_SERVICE);
        SearchView searchView =
                (SearchView) menu.findItem(R.id.search).getActionView();
        searchView.setSearchableInfo(
                searchManager.getSearchableInfo(getComponentName()));

        return true;
    }
    

La llamada a getSearchableInfo() obtiene un objeto SearchableInfo que se crea a partir del archivo XML de la configuración que permite búsquedas. Cuando la configuración que permite búsquedas se asocia de forma correcta con tu SearchView, SearchView inicia una actividad con el intent ACTION_SEARCH cuando un usuario envía una consulta. Ahora necesitas una actividad que sirva como filtro para este intent y administre la búsqueda.

Cómo crear una actividad que permite búsquedas

Un elemento SearchView intenta iniciar una actividad con ACTION_SEARCH cuando un usuario envía una búsqueda. La actividad que permite búsquedas actúa como filtro para el intent ACTION_SEARCH y realiza la búsqueda en algún tipo de conjunto de datos. A fin de crear una actividad que permite búsquedas, declara la actividad que quieras usar para filtrar el intent ACTION_SEARCH:

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

En tu actividad de búsqueda, administra el intent ACTION_SEARCH. Para ello, búscalo en tu método onCreate().

Nota: Si tu actividad que permite búsquedas se inicia en el modo superior único (android:launchMode="singleTop"), también controla el intent ACTION_SEARCH en el método onNewIntent(). En el modo superior único, solo se crea una instancia de tu actividad y las próximas llamadas que se realicen a fin de iniciar una actividad no crearán una nueva actividad en la pila. Este modo de inicio resulta útil a los usuarios porque les permite realizar búsquedas desde la misma actividad sin tener que crear una nueva instancia de actividad cada vez.

Kotlin

    class SearchResultsActivity : Activity() {

        override fun onCreate(savedInstanceState: Bundle?) {
            ...
            handleIntent(intent)
        }

        override fun onNewIntent(intent: Intent) {
            ...
            handleIntent(intent)
        }

        private fun handleIntent(intent: Intent) {

            if (Intent.ACTION_SEARCH == intent.action) {
                val query = intent.getStringExtra(SearchManager.QUERY)
                //use the query to search your data somehow
            }
        }
        ...
    }
    

Java

    public class SearchResultsActivity extends Activity {

        @Override
        public void onCreate(Bundle savedInstanceState) {
            ...
            handleIntent(getIntent());
        }

        @Override
        protected void onNewIntent(Intent intent) {
            ...
            handleIntent(intent);
        }

        private void handleIntent(Intent intent) {

            if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
                String query = intent.getStringExtra(SearchManager.QUERY);
                //use the query to search your data somehow
            }
        }
        ...
    }
    

Si ejecutas tu app ahora, SearchView puede aceptar la consulta del usuario y comenzar tu actividad de búsqueda con el intent ACTION_SEARCH. A partir de aquí, eres responsable de decidir cómo almacenar y buscar tus datos en función a una búsqueda.