web-dev-qa-db-fra.com

Android SearchView.OnQueryTextListener OnQueryTextSubmit n'est pas déclenché sur une chaîne de requête vide

J'utilise Android 4.1.2. J'ai un widget SearchView sur une ActionBar. La documentation sur SearchView.OnQueryTextListener du site de développement Android indique que onQueryTextSubmit est déclenché lorsque "Appelé lorsque l'utilisateur soumet la requête. Cela peut être dû à une pression sur une touche du clavier ou à une pression sur le bouton d'envoi".

Cela ne se produit pas si la requête de recherche est vide. J'ai besoin que cela se déclenche sur une requête vide pour effacer le filtre de recherche d'un ListView. Est-ce un bug ou est-ce que je fais quelque chose de mal?

21
tborja

Ce n'est pas un bug, le code source vérifie délibérément les valeurs nulles et vides:

private void onSubmitQuery() {
    CharSequence query = mQueryTextView.getText();
    if (query != null && TextUtils.getTrimmedLength(query) > 0) {

Cependant, vous devriez pouvoir utiliser le rappel OnQueryTextChange pour effacer les éléments filtrables de votre ListView lorsque l'utilisateur efface la recherche EditText.

13
Sam

ive un travail plus facile autour de:.

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

            @Override
            public boolean onQueryTextChange(String newText) {
                    if (searchView.getQuery().length() == 0) {
                            renderList(true);
                    }
                    return false;
            }
    });
11
James Tan

J'ai eu le même problème et je me suis retrouvé avec la solution suivante: SearchView + OnQueryTextListener.onQueryTextChange personnalisé

SearchView personnalisé:

public class MySearchView extends SearchView {

private boolean expanded;

public MySearchView(Context context) {
    super(context);
}

@Override
public void onActionViewExpanded() {
    super.onActionViewExpanded();
    expanded = true;
}

@Override
public void onActionViewCollapsed() {
    super.onActionViewCollapsed();
    expanded = false;
}

public boolean isExpanded() {
    return expanded;
}
}

Créer une action et définir un rappel: 

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    super.onCreateOptionsMenu(menu, inflater);
    searchAction = menu.add(0, SEARCH_ACTION_ID, 0 , getString(R.string.action_search));
    searchAction.setShowAsAction(SHOW_AS_ACTION_ALWAYS | SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW);       
    searchView = new MySearchView(getSherlockActivity());
    searchView.setOnQueryTextListener(searchQueryListener);
    searchView.setIconifiedByDefault(true);
    searchAction.setActionView(searchView);
}

Et enfin l'auditeur:

private OnQueryTextListener searchQueryListener = new OnQueryTextListener() {
    @Override
    public boolean onQueryTextSubmit(String query) {
        search(query);
        return true;
    }

    @Override
    public boolean onQueryTextChange(String newText) {
        if (searchView.isExpanded() && TextUtils.isEmpty(newText)) {
            search("");
        }

        return true;
    }

    public void search(String query) {
        // reset loader, swap cursor, etc.
    }

};

Testé sur ABS 4.3.

10
Piotr Bazan

J'ai eu le même problème avec SearchView. Ma solution qui consiste à styler SearchView comme indiqué dans guide http://novoda.com/blog/styling-the-actionbar-searchview/ et à définir OnEditorActionListener pour EditText ( Comment déclencher une action lorsque l'utilisateur a appuyé sur entrée? ), qui fait partie de SearchView, était-ce:

final SearchView searchView = (SearchView)findViewById(R.id.search);
int searchPlateId = searchView.getContext().getResources().getIdentifier("Android:id/search_src_text", null, null);
EditText searchPlate = (EditText) searchView.findViewById(searchPlateId);
searchPlate.setOnEditorActionListener(new TextView.OnEditorActionListener() {
    @Override
    public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {

        if (actionId == EditorInfo.IME_ACTION_SEARCH) {
            //Do something
        }
        return false;

    });
9
Jan Hofman

Comme d'autres l'ont mentionné, ce comportement est intentionnel. J'ai abandonné une solution pour OnQueryChangeListener et j'ai décidé de contourner le problème en implémentant OnEditorActionListener dans la EditText du SearchView, auquel vous pouvez accéder en utilisant R.id.search_src_text. Tant que vous setImeOptions de SearchView à EditorInfo.IME_ACTION_SEARCH, vous pouvez gérer un clic sur le bouton de recherche du clavier. Voir cette SO réponse pour plus de détails.

3
theblang

J'ai eu le même problème, puisque les requêtes vides ne sont pas supportées, j'ai dû télécharger et utiliser ActionBarSherlock puis modifier la méthode onSubmitQuery ().

Voici à quoi ressemble onSubmitQuery () maintenant

private void onSubmitQuery() {
     CharSequence query = mQueryTextView.getText();
     if (query == null) {query = "";}
     if (mOnQueryChangeListener == null
             || !mOnQueryChangeListener.onQueryTextSubmit(query.toString())) {
         if (mSearchable != null) {
             launchQuerySearch(KeyEvent.KEYCODE_UNKNOWN, null, query.toString());
             setImeVisibility(false);
         }
         dismissSuggestions();
     }
 }

J'espère que cela t'aides.

1
M3rd0n

Je peux y arriver simplement en implémentant setOnQueryTextListener de la manière suivante:

SearchView searchView = (SearchView) menu.findItem(R.id.searchProductView).getActionView();
    searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
        @Override
        public boolean onQueryTextSubmit(String query) {
            return false;
        }

        @Override
        public boolean onQueryTextChange(String newText) {
            if (TextUtils.isEmpty(newText)) {
                loadLocalData(newText);
            }
            return true;
        }
    });

Où est ma méthode loadLocalData

//query my DB
products = ProductDAO.findByIdList(idList);
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
listView.setLayoutManager(layoutManager);
listView.setAdapter(<YOURADAPTER>)

Cette solution efface votre requête même si vous effacez le texte avec le bouton "X"

0
Giuseppe Sarno

C'est un vieux fil de discussion mais j'ai trouvé une autre solution (code Kotlin, mais fonctionne également en Java):

override fun onQueryTextChange(newText: String?): Boolean {
            if(newText == null || newText.isEmpty())
                searchView.setQuery("\u00A0", false)
            return true
        }

\u00A0 est un caractère qui ressemble à de l'espace, mais pas du point de vue du code. En d'autres termes, SearchView n'est pas vide. Une chaîne vide ou " " ne fonctionnerait pas, car la base SearchView utilise trim, de plus l'utilisateur peut vouloir rechercher du texte se terminant ou commençant par un espace. Mais pour autant que je sache, les utilisateurs ne peuvent pas entrer le caractère \u00A0.

Ensuite, il vous suffit de remplacer getQuery par return super.getQuery.replace("\u00A0", "") dans votre SearchView personnalisé.

0
Miku

Vous ne pouvez pas écraser ce comportement ..__ Une solution de contournement pourrait consister à effacer le filtre lorsqu'un utilisateur quitte la vue de recherche.

Vous pouvez utiliser le OnCloseListener pour cela. Cependant, cela peut également causer des problèmes, en fonction du niveau d'API minimum pour lequel vous développez.

0
GeeF

Dans mon cas, je voulais simplement permettre à l'utilisateur d'effacer sa requête car elle était utilisée comme mot clé dans la recherche d'API. L'idée la plus simple était donc:

    searchView.setOnSearchClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            userQuery = "";
        }
    });

où userQuery est ma variable utilisée pour la recherche, etc.

J'espère que ça aide quelqu'un :)

0
Maik Martinez

Ceci est un hack très sale , mais il fonctionne correctement comme prévu, permettant ainsi l’action de soumission même s’il n’ya pas de texte entré (ou entré puis édité) dans SearchView. 

De manière réfléchie, il obtient un accès à l'écouteur d'action interne de l'éditeur TextView, l'enveloppe dans un écouteur personnalisé dans lequel il délègue l'appel au gestionnaire, puis le définit en tant qu'écouteur d'action du TextView interne.

    Class klass = searchView.getClass();
    try {
        Field currentListenerField = klass.getDeclaredField("mOnEditorActionListener");
        currentListenerField.setAccessible(true);
        TextView.OnEditorActionListener previousListener = (TextView.OnEditorActionListener) currentListenerField.get(searchView);
        TextView.OnEditorActionListener newListener = new TextView.OnEditorActionListener() {
            @Override
            public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
                if (v.getText().length() == 0)
                    handleQuery("");
                return previousListener.onEditorAction(v, actionId, event);
            }
        };
        Field innerTextViewField = klass.getDeclaredField("mSearchSrcTextView");
        innerTextViewField.setAccessible(true);
        SearchView.SearchAutoComplete innerTextView = (SearchView.SearchAutoComplete) innerTextViewField.get(searchView);
        innerTextView.setOnEditorActionListener(newListener);
    } catch (Exception e) {
        throw new IllegalStateException(e);
    }
0
samvel1024

Une autre option consiste à déclencher manuellement la méthode onQueryTextChange via TextWatcher:

public class MyActivity extends Activity implements SearchView.OnQueryTextListener, TextWatcher {

    // Basic onCreate(Bundle) here

    @Override
    public boolean onCreateOptionsMenu (final Menu menu) {
        getMenuInflater().inflate(R.menu.myMenu, menu);

        final SearchView searchView = (SearchView) menu.findItem(R.id.action_search).getActionView();
        final SearchManager manager = (SearchManager) getSystemService(SEARCH_SERVICE);
        searchView.setSearchableInfo(manager.getSearchableInfo(getComponentName()));
        searchView.setOnQueryTextListener(this);

        final int resource_edit_text = searchView.getContext().getResources().getIdentifier("Android:id/search_src_text", null, null);
        ((EditText) searchView.findViewById(resource_edit_text)).addTextChangedListener(this);

        return super.onCreateOptionsMenu(menu);
    }

    // Implementation of TextWatcher, used to have a proper onQueryTextChange (it doesn't update when the last character is removed)
    @Override
    public void beforeTextChanged (final CharSequence charSequence, final int start, final int count, final int after) {}

    @Override
    public void onTextChanged (final CharSequence charSequence, final int start, final int before, final int after) {}

    @Override
    public void afterTextChanged (final Editable editable) {
        if (editable.length() == 0)
            onQueryTextChange(editable.toString());
    }

    // Implementation of OnQueryTextChangeListener

    @Override
    public boolean onQueryTextChange (final String query) {
        // do stuff
        return false;
    }

    @Override
    public boolean onQueryTextSubmit (final String query) {
        // do stuff
        return false;
    }
}

Tout cela va avec tous les fichiers XML par défaut qui ont été abandonnés ici, ce n’est pas le but de cette réponse. Ceci est une solution de contournement que je choisis d'utiliser, n'hésitez pas à utiliser les autres

0
engineercoding