OnCloseListener de SearchView no funciona

101

Estoy tratando de agregar soporte para SearchViewen la ActionBar de Android 3.0+, pero no puedo hacer OnCloseListenerque funcione.

Aquí está mi código:

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.menu, menu);
    searchView = (SearchView) menu.findItem(R.id.search_textbox).getActionView();
    searchView.setOnQueryTextListener(new OnQueryTextListener() {
        @Override
        public boolean onQueryTextChange(String newText) {
            searchLibrary(newText);
            return false;
        }
        @Override
        public boolean onQueryTextSubmit(String query) { return false; }
    });
    searchView.setOnCloseListener(new OnCloseListener() {
        @Override
        public boolean onClose() {
            System.out.println("Testing. 1, 2, 3...");
            return false;
        }
    });
    return true;
}

La búsqueda funciona muy bien y todos funcionan excepto el OnCloseListener. No se imprime nada en Logcat. Aquí está el Logcat para cuando presiono el botón "Cerrar":

02-17 13:01:52.914: I/TextType(446): TextType = 0x0
02-17 13:01:57.344: I/TextType(446): TextType = 0x0
02-17 13:02:02.944: I/TextType(446): TextType = 0x0

Revisé la documentación y las muestras, pero nada pareció cambiarlo. Lo estoy ejecutando en un Asus Transformer Prime y un Galaxy Nexus, ambos en Ice Cream Sandwich. ¿Algunas ideas?

Actualizar:

Sí - System.out.println() hace el trabajo. Aquí tienes la prueba:

   @Override
 public boolean onQueryTextChange(String newText) {
    System.out.println(newText + "hello");
    searchLibrary(newText);
    return false;
 }

Resultados en este Logcat:

02-17 13:04:20.094: I/System.out(21152): hello
02-17 13:04:24.914: I/System.out(21152): thello
02-17 13:04:25.394: I/System.out(21152): tehello
02-17 13:04:25.784: I/System.out(21152): teshello
02-17 13:04:26.064: I/System.out(21152): testhello
Michell Bak
fuente
Hmm, funciona bien para mí con Android 3.2 pero NO para 4.0+
PJL
10
Error
PJL
3
Me alegro de que no sea solo yo quien tenga este problema. ¿Alguien tiene algún otro truco que no sea el siguiente?
bencallis
2
He aprendido dos cosas si showAsActionestá configurado always. El cuadro de búsqueda tiene un botón de cierre propio, pero si está configurado, ifRoom | collapseActionViewse expande en la barra de acciones.
Beraki

Respuestas:

153

También me encuentro con este problema, y ​​no tengo más remedio que renunciar a "oncloselistener". En su lugar, puede obtener su menuItem, entonces setOnActionExpandListener. Luego anule los métodos no implementados.

@Override
public boolean onMenuItemActionExpand(MenuItem item) {
    // TODO Auto-generated method stub
    Log.d("*******","onMenuItemActionExpand");
    return true;
}

@Override
public boolean onMenuItemActionCollapse(MenuItem item) {
    //do what you want to when close the sesarchview
    //remember to return true;
    Log.d("*******","onMenuItemActionCollapse");
    return true;
}
niki huang
fuente
Creo que solo estamos hablando de SearchView de ActionBar, que es solo un panal +
NKijak
no se moleste en usar onCloseListener, solo use este con su elemento de menú.
Robert
12
Creo que puede usar MenuItemCompat.OnActionExpandListener para niveles de API anteriores: developer.android.com/reference/android/support/v4/view/…
Ripityom
2
Respuesta completa:if (Build.VERSION.SdkInt > BuildVersionCodes.NMr1) item.SetOnActionExpandListener(this); else MenuItemCompat.SetOnActionExpandListener(item, this);
FindOutIslamNow
61

Para Android API 14+ (ICS y superior) use este código:

// When using the support library, the setOnActionExpandListener() method is
// static and accepts the MenuItem object as an argument
MenuItemCompat.setOnActionExpandListener(menuItem, new OnActionExpandListener() {
    @Override
    public boolean onMenuItemActionCollapse(MenuItem item) {
        // Do something when collapsed
        return true;  // Return true to collapse action view
    }

    @Override
    public boolean onMenuItemActionExpand(MenuItem item) {
        // Do something when expanded
        return true;  // Return true to expand action view
    }
});

Para obtener más información: http://developer.android.com/guide/topics/ui/actionbar.html#ActionView

Ref: onActionCollapse / onActionExpand

lomza
fuente
31

Para este problema se me ocurrió algo como esto,

private SearchView mSearchView;

@TargetApi(14)
@Override
public boolean onCreateOptionsMenu(Menu menu)
{

    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.conversation_index_activity_menu, menu);

    mSearchView = (SearchView) menu.findItem(R.id.itemSearch).getActionView();

    MenuItem menuItem = menu.findItem(R.id.itemSearch);

    int currentapiVersion = android.os.Build.VERSION.SDK_INT;
    if (currentapiVersion >= android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH)
    {
        menuItem.setOnActionExpandListener(new OnActionExpandListener()
        {

            @Override
            public boolean onMenuItemActionCollapse(MenuItem item)
            {
                // Do something when collapsed
                Log.i(TAG, "onMenuItemActionCollapse " + item.getItemId());
                return true; // Return true to collapse action view
            }

            @Override
            public boolean onMenuItemActionExpand(MenuItem item)
            {
                // TODO Auto-generated method stub
                Log.i(TAG, "onMenuItemActionExpand " + item.getItemId());
                return true;
            }
        });
    } else
    {
        // do something for phones running an SDK before froyo
        mSearchView.setOnCloseListener(new OnCloseListener()
        {

            @Override
            public boolean onClose()
            {
                Log.i(TAG, "mSearchView on close ");
                // TODO Auto-generated method stub
                return false;
            }
        });
    }


    return super.onCreateOptionsMenu(menu);

}
Ben Benson
fuente
1
¿Qué sucede si siempre se ha expandido usando setIconofiedByDefault (falso)? No funciona ... :(
Joan Casadellà
19

Me encontré con el mismo problema en Android 4.1.1. Parece que es un error conocido: https://code.google.com/p/android/issues/detail?id=25758

De todos modos, como solución, utilicé el oyente de cambio de estado (cuando SearchView se separa de la barra de acción, también se cierra obviamente).

view.addOnAttachStateChangeListener(new OnAttachStateChangeListener() {

    @Override
    public void onViewDetachedFromWindow(View arg0) {
        // search was detached/closed
    }

    @Override
    public void onViewAttachedToWindow(View arg0) {
        // search was opened
    }
});

El código anterior funcionó bien en mi caso.


Publico la misma respuesta aquí: https://stackoverflow.com/a/24573266/2162924

Darío
fuente
Sí, ese error se creó justo después de publicar esta pregunta. Vea los comentarios sobre la pregunta original.
Michell Bak
Oh ok, mira ahora. Pero de todos modos, tal vez esta solución con el oyente de cambio de estado también pueda ser útil para otros.
Dario
Si bien es decepcionante que OnCloseListener no funcione como crees, esta es en realidad una solución agradable y limpia. ¡Prestigio!
welshk91
10

Terminé usando un truco que funciona bien para mi propósito, no estoy seguro de que funcione con todos los propósitos. De todos modos, estoy haciendo una verificación para ver si la consulta de búsqueda está vacía. Sin embargo, esto no está realmente relacionado con el de, SearchView¡ OnCloseListenereso todavía no funciona!

searchView.setOnQueryTextListener(new OnQueryTextListener() {
            @Override
            public boolean onQueryTextChange(String newText) {
                if (newText.length() > 0) {
                    // Search
                } else {
                    // Do something when there's no input
                }
                return false;
            }
            @Override
            public boolean onQueryTextSubmit(String query) { return false; }
        });
Michell Bak
fuente
7

Bueno, esto resolvió mi problema:

Elemento de menú con showAsAction="always"

<item
    android:id="@+id/action_search"
    android:icon="@drawable/ic_action_search"
    android:title="Search"
    app:actionViewClass="android.support.v7.widget.SearchView"
    app:showAsAction="always"/>

y en actividad

searchView.setOnCloseListener(new OnCloseListener() {

        @Override
        public boolean onClose() {

            Log.i("SearchView:", "onClose");
            searchView.onActionViewCollapsed();
            return false;
        }
    });
Sushant
fuente
1
Establecer alwaysvalor en showAsActionatributo resuelve el problema. Lo importante es que cuando el alwaysvalor está is notpresente en showAsAction, expandido SearchViewpresenta el botón de cierre (icono de cruz) solo si la consulta en SearchViewno es una cadena nula. El SearchView.onCloseClickedque maneja los eventos del botón de cierre indica que la devolución de llamada a OnCloseListenerse llama solo si la consulta está vacía, si no lo está, se borra primero, pero luego, después de borrar la consulta, el botón de cierre desaparece y no podemos onCloseOnCloseListener
devolver la
1
Solo una pista: este método se llama cuando el usuario cierra la vista de búsqueda (bastante obvio, pero me tomó varias veces darme cuenta). La primera vez que el usuario hace clic en la X, borra el texto, y no obtuve esa actualización, en el segundo clic en la X, cierra SearchView y se invoca onClose. ¡Espero eso ayude!
Federico Alvarez
4

Para que el OnCloseListenertrabajo funcione, asegúrese de que showAsActionesté configurado en alwaysen el elemento del menú de búsqueda.

<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"
      tools:context=".SearchActivity">

    <item
        android:id="@+id/search"
        android:title="@string/search"
        android:icon="@drawable/ic_search_toolbar"
        app:showAsAction="always"
        app:actionViewClass="android.support.v7.widget.SearchView"/>
</menu>
Julio Betta
fuente
2

Me he encontrado con el mismo problema con onCloseListener que no invoca el SearchView. Comprenda el problema del error planteado en 25758 , y algunas publicaciones que he leído, para invocar onCloseListener, debe configurar:

searchView.setIconifiedByDefault(true);

Pero para mi caso, quería tener la vista de búsqueda abierta y no iconificada todo el tiempo. Me las arreglo para resolver esto agregando una línea más a continuación:

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.search_bar, menu);
    SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
    searchView = (SearchView) menu.findItem(R.id.search).getActionView();
    searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));
    searchView.setOnQueryTextListener(queryTextListener);
    searchView.setIconifiedByDefault(true);
    searchView.setIconified(false);
    return true;
}

El searchView.setIconified (false) hará que el searchView se abra, a pesar de establecer el valor predeterminado en iconified como verdadero en la línea anterior. De esta manera, logré tener un SearchView que se abre todo el tiempo y que invoque el onCloseListener.

gkl
fuente
2

Cree el elemento del menú con el app:showAsActionajuste siempre.

<item   
 android:id="@+id/action_search"  
 android:title="..."  
 android:icon="..."  
 app:actionViewClass="android.support.v7.widget.SearchView"  
 app:showAsAction="always"/>

Al crear el SearchViewen el onCreateOptionsMenumétodo, haga algo similar

inflater.inflate(R.menu.menu_search, menu);
final MenuItem item = menu.findItem(R.id.action_search);
final SearchView search = (SearchView) item.getActionView();
search.setQueryHint(getString(R.string.search_brand_item));
search.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
  @Override
  public boolean onQueryTextSubmit(String query) {
    // add your code
    return false;
  }

  @Override
  public boolean onQueryTextChange(String newText) {
    // add your code 
    return false;
  }
});
search.setOnCloseListener(new SearchView.OnCloseListener() {
  @Override
  public boolean onClose() {
    // add your code here
    return false;
  }
});
search.setIconifiedByDefault(true); // make sure to set this to true

Las search.setIconifiedByDefault(true)necesidades que se establezcan a truellamar al onClose()método en la SearchView.OnCloseListener()creada anteriormente.

Ray Hunter
fuente
0

La razón por la OnCloseListenerque no se llama es porque hay un error en el código de Android: solo se llama al oyente si también llama setIconifiedByDefault(true).

Joseph Earl
fuente
7
Intenté agregar setIconifiedByDefault (verdadero) pero no se llama
Giuseppe
@Joseph Earl: Tengo un problema similar aquí: stackoverflow.com/questions/43702055/… . ¿Algún pensamiento o idea sobre cómo solucionarlo?
AJW
0

Ya parece un hilo antiguo, pero pensé que tenía el mismo problema API 18 al principio. Después de buscar en Google, encontré este hilo, otra hora leyó el javadoc probado y erró por algo que no pretendo entender completamente en javadoc, el siguiente trabajo para mí ahora:

searchView.setIconifiedByDefault(true);

   // OnQueryTextListener
   @Override
   public boolean onQueryTextSubmit(String query) {
      Log.d(tag, "onQueryTextSubmit: " + query);
      return true;
   }

   @Override
   public boolean onQueryTextChange(String query) {
      Log.d(tag, "onQueryTextChange: " + query);
      return true;
   }

   // OnCloseListener
   @Override
   public boolean onClose() {
      Log.w(tag, "onClose: ");
      return false;
   }

Jugué un poco con verdadero / falso, eso de alguna manera hace la diferencia, y ahora funciona para mí. Con suerte, podría ahorrarle tiempo a alguien.

Sean
fuente
0

Es una solución pero me ha funcionado

  searchView.setOnQueryTextListener(new android.widget.SearchView.OnQueryTextListener() {

                String lastText;

                @Override
                public boolean onQueryTextChange(final String newText) {
                    if (lastText != null && lastText.length() > 1 && newText.isEmpty()) {
                        // close ctn clicked

                        return true;
                    }
}
Nativ
fuente
0
    searchView.setOnCloseListener {
        d("click", "close clicked")
        return@setOnCloseListener false
    }

si hace clic en cerrar searchView ->

D / clic: cerrar clic

Oleksandr Yahnenko
fuente
1
Las respuestas con un fragmento de código y algunas palabras crípticas no son particularmente claras. Simplemente use un lenguaje natural para describir por qué cree que esto resuelve el problema y luego muestre la implementación de la solución.
0

Encontré este problema al intentar detectar la visualización o el rechazo de SearchView. Terminé usando un oyente diferente y funcionó para lo que necesito:

        setOnQueryTextFocusChangeListener { _, hasFocus ->
            if (hasFocus) {
                // SearchView is being shown
            } else {
                // SearchView was dismissed
            }
        }
Psylocke
fuente
0

Usé el botón de cierre de SearchView y configuré un setOnClickListener en él

searchView.findViewById<ImageView>(R.id.search_close_btn).setOnClickListener {
    searchView.setQuery("", false)
    searchView.clearFocus()
}
Alejandro
fuente
-2

No hay ninguna consola en Android para iniciar sesión. En su lugar, use el marco de registro de Android:

Log.d("Test Tag", "Testing.  1, 2, 3...");

Consulte también esta pregunta: ¿Por qué "System.out.println" no funciona en Android?

Chris Knight
fuente
2
No es cierto, funciona bien. Consulte mi pregunta actualizada: agregué una línea en el método onQueryTextChange para demostrarlo. También intenté agregar Log.d (), pero tampoco mostró nada.
Michell Bak
¡Oh mi error! Parece que en algún punto del camino han decidido enviar System.out.println al Log.i. Buena suerte
Chris Knight
-3

Hay dos patrones comunes para SearchView.setOnCloseListener(). Esto es realmente cierto para todos los oyentes, pero me dirijo a su pregunta específicamente. La primera forma es crear una función de escucha y adjuntarla a una variable miembro, y la segunda es hacer que la clase implemente la interfaz y que el controlador sea una función miembro.

La creación de un objeto de escucha se ve así:

private SearchView mSearchView;
private final SearchView.OnCloseListener mOnCloseListener = 
    new SearchView.OnCloseListener() {
        public boolean onClose() {
            doStuff();
            return myBooleanResult;
        }
    };
mSearchView.setOnCloseListener(mOnCloseListener);

La implementación del oyente a nivel de clase se ve así:

public class MyClass implements OnCloseListener {
    private SearchView mSearchView;

    public MyClass(...) {
        mSearchView.setOnCloseListener(this);
    }

    @Override
    public boolean onClose() {
        doStuff();
        return false;
    }
}

No he visto ningún ejemplo que cree el OnCloseListenerad-hoc, como lo hizo en su pregunta.

Sparky
fuente
Hola Sparky, gracias por comentar esto. Realmente no veo cómo eso debería cambiar algo. Un oyente anidado también es una forma válida de hacerlo, y funciona en Honeycomb como puede ver en base a los comentarios aquí. No he tenido ningún problema con los oyentes anidados en ICS aparte de esto, que nuevamente funciona en Honeycomb.
Michell Bak
Por oyentes anidados me refiero a clases internas anónimas.
Michell Bak
Estoy de acuerdo en que no debería importar. Solo estoy comentando lo que está presente en el código base. Buscaré y veré si tal vez se redefinieron las condiciones en las que onClose.
Sparky
No estoy seguro de que entiendas Java; se llama clase interna anónima.
Joseph Earl