OnCloseListener de SearchView ne fonctionne pas

101

J'essaie d'ajouter la prise en charge de la SearchViewbarre d'action Android 3.0+, mais je ne parviens pas à faire OnCloseListenerfonctionner le.

Voici mon code:

@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 recherche fonctionne très bien et tout fonctionne à l'exception du OnCloseListener. Rien n'est imprimé sur Logcat. Voici le Logcat lorsque j'appuie sur le bouton "Fermer":

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

J'ai parcouru la documentation et les exemples, mais rien n'a semblé le changer. Je l'exécute sur un Asus Transformer Prime et un Galaxy Nexus, tous deux sur Ice Cream Sandwich. Des idées?

Mettre à jour:

Oui, System.out.println() ça marche. Voici la preuve:

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

Résultats dans ce 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
la source
Hmm, fonctionne bien pour moi avec Android 3.2 mais PAS pour 4.0+
PJL
10
Bug soulevé, 25758
PJL
3
Je suis content que ce ne soit pas seulement moi qui ai ce problème. Quelqu'un a-t-il d'autres hacks que celui ci-dessous?
bencallis
2
J'ai appris deux choses si showAsActionest réglé sur always. La zone de recherche a son propre bouton de fermeture, mais si elle est définie, ifRoom | collapseActionViewelle se développe dans la barre d'action.
Beraki

Réponses:

153

Je rencontre également ce problème, et je n'ai pas d'autre choix que de renoncer à "oncloselistener". Au lieu de cela, vous pouvez obtenir votre menuItem, alors setOnActionExpandListener. Remplacez ensuite les méthodes non implémentées.

@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
la source
Je crois que nous ne parlons que de SearchView d'ActionBar qui n'est que du nid d'abeille +
NKijak
ne vous embêtez pas à utiliser onCloseListener, utilisez simplement celui-ci avec votre élément de menu.
Robert
12
Je pense que vous pouvez utiliser MenuItemCompat.OnActionExpandListener pour les niveaux d'API antérieurs: developer.android.com/reference/android/support/v4/view/…
Ripityom
2
Réponse complète:if (Build.VERSION.SdkInt > BuildVersionCodes.NMr1) item.SetOnActionExpandListener(this); else MenuItemCompat.SetOnActionExpandListener(item, this);
FindOutIslamNow
61

Pour l'API Android 14+ (ICS et supérieur), utilisez ce code:

// 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
    }
});

Pour plus d'informations: http://developer.android.com/guide/topics/ui/actionbar.html#ActionView

Réf: onActionCollapse / onActionExpand

Lomza
la source
31

Pour ce problème, j'ai trouvé quelque chose comme ça,

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
la source
1
Que se passe-t-il si vous avez toujours développé avec setIconofiedByDefault (false)? Ça ne marche pas ... :(
Joan Casadellà
19

J'ai rencontré le même problème sur Android 4.1.1. On dirait qu'il s'agit d'un bogue connu: https://code.google.com/p/android/issues/detail?id=25758

Quoi qu'il en soit, comme solution de contournement, j'ai utilisé un écouteur de changement d'état (lorsque SearchView est détaché de la barre d'action, il est également fermé évidemment).

view.addOnAttachStateChangeListener(new OnAttachStateChangeListener() {

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

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

Le code ci-dessus a bien fonctionné dans mon cas.


Je poste la même réponse ici: https://stackoverflow.com/a/24573266/2162924

Dario
la source
Oui, ce bogue a été créé juste après avoir publié cette question. Voir les commentaires sur la question initiale.
Michell Bak le
Oh ok, vois maintenant. Mais de toute façon, peut-être que cette solution de contournement avec l'écouteur de changement d'état pourrait être utile pour d'autres également.
Dario
Bien que décevant qu'OnCloseListener ne fonctionne pas comme vous le pensez, il s'agit en fait d'une solution agréable et propre. Gloire!
welshk91
10

J'ai fini par utiliser un peu de hack, cela fonctionne bien pour mon objectif - pas sûr que cela fonctionnera à toutes les fins. Quoi qu'il en soit, je vérifie si la requête de recherche est vide. Ce n'est pas vraiment lié au SearchView's OnCloseListenercependant - cela ne fonctionne toujours pas!

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
la source
7

Eh bien, cela a résolu mon problème:

Élément de menu avec 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"/>

et en activité

searchView.setOnCloseListener(new OnCloseListener() {

        @Override
        public boolean onClose() {

            Log.i("SearchView:", "onClose");
            searchView.onActionViewCollapsed();
            return false;
        }
    });
Sushant
la source
1
La définition de la alwaysvaleur showAsActionattributaire résout le problème. L'important est que lorsque la alwaysvaleur is notprésente dans showAsAction, développé SearchViewprésente le bouton de fermeture (icône en forme de croix) uniquement si la requête dans SearchViewest une chaîne non nulle. Le SearchView.onCloseClickedqui gère les événements du bouton de fermeture indique que le rappel à OnCloseListenern'est appelé que si la requête est vide, si ce n'est pas le cas - il est d'abord effacé - mais ensuite, après avoir effacé la requête, le bouton de fermeture disparaît et nous ne pouvons pas fournir de onCloserappel àOnCloseListener
bpawlowski
1
Juste un indice: cette méthode est appelée lorsque l'utilisateur ferme la vue de recherche (assez évident, mais il m'a fallu plusieurs fois pour m'en rendre compte). La première fois que l'utilisateur clique sur le X, il efface le texte, et je n'ai pas obtenu cette mise à jour, au deuxième clic sur le X, il ferme SearchView et onClose est appelé. J'espère que ça aide!
Federico Alvarez
4

Afin de faire le OnCloseListenertravail, assurez-vous que showAsActionest défini sur alwaysdans l'élément de menu de recherche.

<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
la source
2

J'ai rencontré le même problème avec onCloseListener qui n'appelle pas pour SearchView. Comprenez à partir du problème de bogue soulevé dans 25758 et de certains messages que j'ai lus pour appeler onCloseListener, vous devez définir:

searchView.setIconifiedByDefault(true);

Mais pour mon cas, je voulais que la vue de recherche soit ouverte et non iconifiée tout le temps. Je parviens à résoudre ce problème en ajoutant une ligne supplémentaire ci-dessous:

@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;
}

Le searchView.setIconified (false) provoquera l'ouverture de searchView, malgré la définition de la valeur par défaut sur iconified sur true dans la ligne précédente. De cette façon, j'ai réussi à avoir à la fois un SearchView qui s'ouvre tout le temps et à l'invoquer onCloseListener.

gkl
la source
2

Créez l'élément de menu avec la valeur app:showAsActiontoujours.

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

Lors de la création SearchViewde la onCreateOptionsMenuméthode, faites quelque chose de similaire

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

Le search.setIconifiedByDefault(true)doit être défini sur truepour appeler la onClose()méthode sur le SearchView.OnCloseListener()créé ci-dessus.

Ray Hunter
la source
1

Pour le MenuItemCompatproblème, j'ai ajouté ViewTreeObserver pour suivre l'état de visibilité. Vous pouvez vérifier ma réponse ici: https://stackoverflow.com/a/28762632/1633609

Sir NIkolay Cesar le premier
la source
0

La raison pour laquelle le OnCloseListenern'est pas appelé est qu'il y a un bogue dans le code Android - l'auditeur n'est appelé que si vous appelez également setIconifiedByDefault(true).

Joseph Earl
la source
7
J'ai juste essayé d'ajouter setIconifiedByDefault (true) mais il ne s'appelle pas
Giuseppe
@Joseph Earl: J'ai un problème similaire ici: stackoverflow.com/questions/43702055/… . Des pensées ou des idées sur la façon de résoudre le problème?
AJW
0

semble déjà un vieux fil, mais je pensais avoir le même problème API 18 au premier début. Après avoir cherché sur Google, trouvé ce fil, une autre heure a lu le javadoc essayé et a commis une erreur pour quelque chose que je ne prétends pas comprendre pleinement en javadoc, le travail suivant pour moi maintenant:

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;
   }

J'ai joué un peu avec vrai / faux, ça fait en quelque sorte la différence, et ça marche pour moi maintenant. Espérons que cela pourrait faire gagner du temps à quelqu'un.

Sean
la source
0

C'est une solution de contournement mais cela a fonctionné pour moi

  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
la source
0
    searchView.setOnCloseListener {
        d("click", "close clicked")
        return@setOnCloseListener false
    }

si vous cliquez sur fermer la rechercheView ->

D / clic: fermer cliqué

Oleksandr Yahnenko
la source
1
Les réponses avec une goutte de code et des mots cryptiques ne sont pas particulièrement claires. Utilisez simplement un langage naturel pour décrire pourquoi vous pensez que cela résout le problème, puis montrez l'implémentation de la solution.
0

J'ai rencontré ce problème en essayant de détecter l'affichage / le rejet de SearchView. J'ai fini par utiliser un auditeur différent et cela a fonctionné pour ce dont j'avais besoin:

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

J'ai utilisé le bouton de fermeture SearchView et défini un setOnClickListener dessus

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

Il n'y a pas de console dans Android pour se connecter. Utilisez plutôt le cadre de journalisation Android:

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

Voir aussi cette question: Pourquoi "System.out.println" ne fonctionne-t-il pas sous Android?

Chris Knight
la source
2
Pas vrai, cela fonctionne très bien. Veuillez consulter ma question mise à jour - j'ai ajouté une ligne dans la méthode onQueryTextChange pour le prouver. J'ai également essayé d'ajouter Log.d (), mais cela n'affichait rien non plus.
Michell Bak
Oh, mon mauvais! On dirait que quelque part en cours de route, ils ont décidé de générer System.out.println dans le Log.i. Bonne chance
Chris Knight
-3

Il existe deux modèles courants pour SearchView.setOnCloseListener(). C'est vraiment vrai pour tous les auditeurs, mais je réponds spécifiquement à votre question. La première consiste à créer une fonction d'écoute et à l'attacher à une variable membre, et la seconde consiste à faire en sorte que la classe implémente l'interface et que le gestionnaire soit une fonction membre.

La création d'un objet écouteur ressemble à ceci:

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

L'implémentation de l'écouteur au niveau de la classe ressemble à ceci:

public class MyClass implements OnCloseListener {
    private SearchView mSearchView;

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

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

Je n'ai vu aucun exemple qui crée l' OnCloseListenerad-hoc, comme vous l'avez fait dans votre question.

Sparky
la source
Hé Sparky, merci d'avoir commenté cela. Je ne vois pas vraiment comment cela devrait changer quoi que ce soit. Un auditeur imbriqué est également un moyen valide de le faire, et cela fonctionne sur Honeycomb comme vous pouvez le voir en vous basant sur les commentaires ici. Je n'ai eu aucun problème avec les écouteurs imbriqués sur ICS autre que celui-ci - qui fonctionne encore une fois sur Honeycomb.
Michell Bak
Par écouteurs imbriqués, j'entends des classes internes anonymes.
Michell Bak
Je suis d'accord que cela ne devrait pas avoir d'importance. Je ne fais que commenter ce qui est présent dans la base de code. Je vais regarder et voir si les conditions dans lesquelles onClose ont été redéfinies.
Sparky
Je ne suis pas sûr que vous compreniez Java - cela s'appelle une classe interne anonyme.
Joseph Earl