Cerrar automáticamente la barra de acciones SearchView en el cierre del teclado virtual

79

Actualmente estoy usando un elemento del menú ActionBar para mostrar un SearchView en la barra de acciones. Cuando se expande el elemento del menú de búsqueda, se muestra el teclado virtual, que es lo que quiero. Ahora, cuando el usuario presiona el botón Atrás para cerrar el teclado en pantalla, también me gustaría colapsar SearchView en la barra de acción.

Intenté implementar los siguientes oyentes OnKeyListener y OnFocusChangeListener en MenuItem y ActionView. También intenté usar OnBackPressed () en la Actividad. Ninguno de los anteriores detecta cuándo se usa el botón Atrás para cerrar el teclado virtual.

¿Algunas ideas?

Implementé OnActionExpandListener para saber cuándo está visible SearchView.

usuario1258568
fuente
Aquí hay una respuesta muy popular stackoverflow.com/questions/1109022/…
jmishra
2
no lo ayudará, necesita interceptar la tecla de retroceso del teclado
dor506
@acrespo ¿Qué respuesta? Comentas una pregunta ...
El increíble

Respuestas:

100

Ampliaré la respuesta de @ user1258568 para los vagos. Esto funcionó para mí. Tenga en cuenta que borra su consulta cuando se pierde el foco.

final MenuItem searchMenuItem = optionsMenu.findItem(R.id.search);
final SearchView searchView = (SearchView) searchMenuItem.getActionView();

searchView.setOnQueryTextFocusChangeListener(new View.OnFocusChangeListener() {
    @Override
    public void onFocusChange(View view, boolean queryTextFocused) {
        if(!queryTextFocused) {
            searchMenuItem.collapseActionView();
            searchView.setQuery("", false);
        }
    }
});
Jon Willis
fuente
1
Funciona perfectamente. Si agrega un searchView en el código, es posible que deba usar menu.getItem(yourSearchViewItemPosition)en su lugar.
GeeF
@AlexBonel ¿Cómo es eso? Sé que el S3 y el S4 tienen botones de hardware idiotas, pero no tengo claro cómo afectaría eso a este fragmento. Quizás sea porque el menú ActionBar está oculto y searchMenuItem actúa de manera diferente. Tengo un S4 a mano, tendré que probarlo.
Jon Willis
@JonWillis Si no es difícil para ti, ¿podrías compartir tu experiencia de tal comportamiento en S4, por favor?
Alex Bonel
4
Bien, después de horas de investigación e implementaciones para intentar hacer esto, encontré tu respuesta :) ... Lo primero que pensé fue usar un oyente de enfoque pero usé en setOnFocusChangeListener()lugar de setOnQueryTextFocusChangeListener(). Con tu método todo funciona bien. Gracias.
Ionut Negru
2
@IonutNegru ¡de nada! a veces me encanta el SDK de Android. Quiero verlos reescribirlo de una manera sensata y moderna y dejar el soporte heredado, pero eso nunca sucederá.
Jon Willis
37

Encontré una mejor solución.

searchView.setOnQueryTextFocusChangeListener(). 

Se OnQueryTextFocusChangeListenerllama cuando el teclado se muestra u oculta. Se llama primero cuando se muestra el teclado y la vista de búsqueda tendrá el foco. Se vuelve a llamar cuando keyboardestá oculto y la vista de búsqueda perderá el foco, close search viewluego puede usar

menuItem.collapseActionView().
usuario1258568
fuente
5
Esto es engañoso. El OnQueryTextFocusChangeListenerNO se consiga llamar cuando se muestra u oculta el teclado. Se llama solo cuando searchViewentra en foco o se desenfoca. Por lo tanto, cuando SearchViewestá enfocado por primera vez, OnQueryTextFocusChangeListenerse llama y también se muestra el teclado. Ahora, si se presiona el botón Atrás, el teclado se oculta pero OnQueryTextFocusChangeListenerno se llama. Al presionar el botón Atrás por segunda vez, se searchViewcolapsa y OnQueryTextFocusChangeListenerse llama.
faizal
11

Simplemente anule onBackPressed así:

@Override
    public void onBackPressed() {
        if (searchView.isShown()){
            searchView.onActionViewCollapsed();  //collapse your ActionView
            searchView.setQuery("",false);       //clears your query without submit
            isClosed = true;                     //needed to handle closed by back
        } else{
            super.onBackPressed();
        }
    }

y su onCreateOptionsMenu inflaría el mSearchView de esta manera:

@Override
    public boolean onCreateOptionsMenu(Menu menu) {
        super.onCreateOptionsMenu(menu);
        getMenuInflater().inflate(R.menu.menu_search, menu);
        mSearchView = (SearchView) menu.findItem(R.id.menu_action_search).getActionView();
        mSearchView.setOnQueryTextListener(this);
        mSearchView.setOnSearchClickListener(this);
        mSearchView.setOnCloseListener(this);
        isClosed = true;
        return true;
    }

¿Ha implementado su clase lo siguiente así:

public class myActivity extends FragmentActivity implements
    SearchView.OnQueryTextListener, View.OnClickListener, SearchView.OnCloseListener {

que también necesitarás:

@Override
public void onClick(View view) {
    isClosed = false;
}

@Override
public boolean onClose() {
    isClosed = true;
    return false;
}

Deberá hacer que "mSearchView" y "isClosed" sean ambas variables globales para la actividad.

Codificado
fuente
3
No creo que eso funcione; en mi experiencia, el método onBackPressed no se llama si el teclado está arriba; simplemente descarta el teclado y debe presionar atrás nuevamente para que llame a ese método. Esto está en 2.3; No he experimentado con 3.xy 4.0, pero sospecho que esto también es lo mismo.
Kevlar
@Kevlar Creo que puede tener razón. Probaré esto nuevamente y me aseguraré de que no haya una manera. Parece que mi solución es ligeramente diferente de lo que quieren. Hasta donde yo sé, no creo que haya una manera de manejar ningún respaldo mientras se muestra el teclado virtual. Mi solución se maneja después de que el teclado está cerrado con seguridad. Probará en diferentes SDK.
Codeversed
1
había intentado contraer la búsqueda usando: searchMenuItem.collapseActionView (); pero resultó que searchView.onActionViewCollapsed (); me hizo el truco - ¡gracias!
bkurzius
No creo que debas llamar directamente a ... funciones. Esas funciones no están hechas para ser llamadas directamente desde su código ...
user457015
cómo usar collapseActionView () en el nivel de api 11.
madan V
3

La respuesta de Jon Willis funciona muy bien. Esta es una mejora a su respuesta.

Primero, cree una nueva clase que implemente View.OnFocusChangeListener:

public class SearchViewFocusListener implements View.OnFocusChangeListener {

    private final MenuItem mMenuItem;

    public SearchViewFocusListener(MenuItem menuItem) {
        mMenuItem = menuItem;
    }

    @Override
    public void onFocusChange(View v, boolean hasFocus) {
        if (!hasFocus) {
            mMenuItem.collapseActionView();
            if (v instanceof SearchView) {
                ((SearchView) v).setQuery("", false);
            }
        }
    }

}

A continuación, configure el oyente en su SearchView:

searchView.setOnQueryTextFocusChangeListener(new SearchViewFocusListener(menuItem));
Jared Rummler
fuente
funciona bien, pero ¿cómo borro el foco del icono de búsqueda? El FocusChangeListener captura una presión del botón Atrás en un dispositivo y eso cierra el teclado virtual y cierra el SearchView y luego aparece el ícono de búsqueda como me gustaría. Sin embargo, el icono de búsqueda está resaltado (tiene foco) y prefiero que no tenga foco. Intenté varias formas de despejar, pero sin suerte. ¿Algunas ideas?
AJW
2

Solo necesita poner el atributo "collapseActionView" en el diseño del menú

<menu xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:app="http://schemas.android.com/apk/res-auto">
    <item
        android:id="@+id/menu_item_search"
        android:title="@string/search"
        android:iconifiedByDefault="true"
        android:icon="@drawable/ic_action_search" 
        app:actionViewClass="android.support.v7.widget.SearchView"
        app:showAsAction="ifRoom|collapseActionView"/> <--this one
</menu>

Eso le dará la funcionalidad que busca por sí solo. No olvide llamar al método "clearFocus" en SearchView para cerrar el teclado una vez que envíe la consulta.

Rodrigo de Blas
fuente
1

Esto es lo que hice para hacer desaparecer el teclado. Puede intentar ver si esto funciona para usted. Configuré el searchViewen invisible y luego en visible nuevamente.

    //set query change listener
     searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener(){
        @Override
        public boolean onQueryTextChange(String newText) {
            // TODO Auto-generated method stub
            return false;
        }

        @Override
        public boolean onQueryTextSubmit(String query) {
            /**
             * hides and then unhides search tab to make sure keyboard disappears when query is submitted
             */
                  searchView.setVisibility(View.INVISIBLE);
                  searchView.setVisibility(View.VISIBLE);
            return false;
        }

     });
Parnit
fuente
También funcionó para mí, pero debes agregar getActivity (). SupportInvalidateOptionsMenu (); para restaurar la barra de acción
almisoft
1

Se puede lograr así:

   private void setupSearchView(Menu menu) {
        final MenuItem searchMenuItem = menu.findItem(R.id.action_search);
        final SearchView searchView = (SearchView) searchMenuItem.getActionView();

        [...]

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

Las soluciones basadas en setOnQueryTextFocusChangeListener () no funcionaron para mí porque el evento no se lanzó; el searchView no perdió el foco cuando se envió, probablemente porque realizo la búsqueda en la misma actividad que contiene el Search View.

De todos modos, creo que usar OnQueryTextListener es más correcto, ya que describe el evento de enviar texto con mayor precisión.

GaRRaPeTa
fuente
0
@Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getSupportMenuInflater().inflate(R.menu.home_screen, menu);

        SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
        final MenuItem searchMenuItem = menu.findItem(R.id.menu_search);
        final SearchView searchView = (SearchView) searchMenuItem
                .getActionView();
        searchView.setIconifiedByDefault(false);
        if (searchManager != null && searchView != null) {
            searchView.setSearchableInfo(searchManager
                    .getSearchableInfo(getComponentName()));

            searchView
                    .setOnQueryTextFocusChangeListener(new View.OnFocusChangeListener() {

                        @Override
                        public void onFocusChange(View v, boolean hasFocus) {

                            if (!hasFocus) {
                                if (searchMenuItem != null) {
                                    searchMenuItem.collapseActionView();
                                }// end if
                                if (searchView != null) {
                                    searchView.setQuery("", false);

                                }// end if
                            }// end if

                        }
                    });

            searchView
                    .setOnQueryTextListener(new SearchView.OnQueryTextListener() {

                        @Override
                        public boolean onQueryTextSubmit(String query) {
                            /**
                             * hides and then unhides search tab to make sure
                             * keyboard disappears when query is submitted
                             */
                            if (searchView != null) {
                                searchView.setVisibility(View.INVISIBLE);
                                searchView.setVisibility(View.VISIBLE);

                            }
                            return false;
                        }

                        @Override
                        public boolean onQueryTextChange(String newText) {
                            // TODO Auto-generated method stub
                            return false;
                        }
                    });

        }

        return super.onCreateOptionsMenu(menu);
    }
Confucio
fuente
0

Si desea contraer el teclado cuando el usuario hace clic en el icono de búsqueda en el teclado, esto se puede lograr simplemente

inside onquerytextsubmitted {

searchView.clearfocus()

}

geniushkg
fuente
0

Debe llamar a setIconified dos veces.

Para contraer realmente la vista de búsqueda y cerrar el teclado.
Con la primera llamada, el texto de la vista de búsqueda se borra con el teclado de la segunda llamada y la vista de búsqueda se cierra.

nosaiba darwish
fuente
0

Por alguna razón, menuItem.collapseActionView()no funcionó, así que usé en su searchView.setIconified(true)lugar.

Esto da el resultado siguiente como ejemplo de código.

final MenuItem searchItem = (MenuItem) menu.findItem(R.id.menu_item_search);
final SearchView searchView = (SearchView) searchItem.getActionView();

searchView.setOnQueryTextFocusChangeListener(new SearchView.OnFocusChangeListener() {
    @Override
    public void onFocusChange(View v, boolean hasFocus) {
        if (!hasFocus) {
            searchView.setIconified(true);
        }
    }
});
bastien
fuente