Android SearchView.OnQueryTextListener OnQueryTextSubmit not fired on empty query string

后端 未结 13 841
盖世英雄少女心
盖世英雄少女心 2020-12-05 10:17

I am using Android 4.1.2. I have a SearchView widget on an ActionBar. Documentation on SearchView.OnQueryTextListener

相关标签:
13条回答
  • 2020-12-05 10:35

    This is a very dirty hack, however it works correctly as expected, enabling the submit action even when there is no text entered (or entered then edited) in the SearchView.

    It reflectively gains access to the inner TextView editor action listener, wraps it in a custom listener where it delegates the call to the handler, and finally sets it as the action listener of the inner TextView.

        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 讨论(0)
  • 2020-12-05 10:36

    It's an old thread but I've found another solution (Kotlin code, but works in Java as well):

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

    \u00A0 is a character that looks like space, but code-wise it is not. In other words SearchView is not empty. Empty string or " " would not work, because base SearchView uses trim, plus user may want to search text ending or beginning with space. But as far as I know users cannot enter \u00A0 character.

    Then all you need to do is override getQuery to return super.getQuery.replace("\u00A0", "") in your custom SearchView

    0 讨论(0)
  • 2020-12-05 10:36

    This is a complete example written in Kotlin:

    import android.content.Context
    import android.text.TextUtils
    import android.util.AttributeSet
    import android.view.inputmethod.EditorInfo
    import android.widget.TextView
    import androidx.appcompat.widget.SearchView
    
    /**
     * Custom [SearchView] which can listen to empty submit events
     *
     * If the internal implementation would change, this will not crash at runtime. It will simply
     * ignore the empty submit listener and will continue to work as this is the base [SearchView]
     */
    class EmptySubmitSearchView @JvmOverloads constructor(
        context: Context,
        attrs: AttributeSet? = null,
        defStyleAttr: Int = 0
    ) : SearchView(context, attrs, defStyleAttr) {
    
        private lateinit var searchAutoComplete: SearchAutoComplete
    
        private lateinit var internalEditorListener: TextView.OnEditorActionListener
    
        private var emptySubmitListener: OnEmptySubmitListener? = null
    
        init {
            try {
                val defaultListenerField = SearchView::class.java
                    .getDeclaredField("mOnEditorActionListener")
                defaultListenerField.isAccessible = true
                internalEditorListener = defaultListenerField.get(this) as TextView.OnEditorActionListener
    
                val searchAutoCompleteField = SearchView::class.java
                    .getDeclaredField("mSearchSrcTextView")
                searchAutoCompleteField.isAccessible = true
                searchAutoComplete = searchAutoCompleteField.get(this) as SearchAutoComplete
    
                searchAutoComplete.setOnEditorActionListener { v, actionId, event ->
                    if (actionId == EditorInfo.IME_ACTION_DONE && TextUtils.isEmpty(searchAutoComplete.text)) {
                        emptySubmitListener?.onEmptyTextSubmit()
                    } else {
                        internalEditorListener.onEditorAction(v, actionId, event)
                    }
                    true
                }
            } catch (ignored: Exception) {
                //Some internal field has changed. Check there is a field called
                //mSearchSrcTextView and mOnEditorActionListener and if not update them accordingly
            }
        }
    
        /**
         * Set custom empty listener or null to remove it
         */
        fun setOnEmptySubmitListener(listener: OnEmptySubmitListener?) {
            emptySubmitListener = listener
        }
    
        interface OnEmptySubmitListener {
            fun onEmptyTextSubmit()
        }
    }
    

    You can set a custom listener with setOnEmptySubmitListener which will enable you to distinguish between events.

    You can customize the actionId to respond to, in this case I had in my XML the EmptySubmitSearchView with this android:imeOptions="actionDone|flagNoExtractUi"

    0 讨论(0)
  • 2020-12-05 10:37

    It is not a bug, the source code deliberately checks against null and empty values:

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

    However you should be able to use the OnQueryTextChange callback to clear your ListView's filterables when the user clears the search EditText.

    0 讨论(0)
  • 2020-12-05 10:41

    I had same issue with SearchView. My solution which consists of styling SearchView as shown in guide http://novoda.com/blog/styling-the-actionbar-searchview/ and setting OnEditorActionListener for EditText( How do I trigger an action when the user has hit enter?) which is part of the SearchView was this:

    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;
    
        }});
    
    0 讨论(0)
  • 2020-12-05 10:42

    You cannot overwrite this behavior. A workaround could be to clear the filter, when a user exits the searchview.

    You could use the OnCloseListener for this. However, this can cause problems as well, depending on the minimum API Level you are developing for.

    0 讨论(0)
提交回复
热议问题