Android SearchView.OnQueryTextListener OnQueryTextSubmit 未在空



我正在使用Android 4.1.2。我在ActionBar上有一个SearchView小部件.Android 开发者网站上的SearchView.OnQueryTextListener文档指出,当用户提交查询时,onQueryTextSubmit被触发/调用。这可能是由于按下键盘上的键或按下提交按钮。

如果搜索查询为空,则不会发生这种情况。我需要在空查询上触发它以清除 ListView 的搜索过滤器。这是一个错误还是我做错了什么?

这不是错误,源代码故意检查空值和空值:

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

但是,当用户清除搜索 EditText 时,您应该能够使用 OnQueryTextChange 回调来清除 ListView 的可筛选对象。

我有一个更简单的解决方法:使用onQueryTextChange,但仅在它为空时才呈现。

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

我遇到了同样的问题,最终得到了以下解决方案:自定义SearchView + OnQueryTextListener.onQueryTextChange

自定义搜索视图:

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

创建动作和设置回调:

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

最后是听众:

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

在 ABS 4.3 上测试。

我在搜索视图上遇到了同样的问题。我的解决方案包括样式搜索视图,如指南 http://novoda.com/blog/styling-the-actionbar-searchview/所示,并为EditText设置OnEditorActionListener(当用户按回车键时如何触发操作?),这是SearchView的一部分:

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

这是一个旧线程,但我找到了另一种解决方案(Kotlin 代码,但也适用于 Java):

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

u00A0是一个看起来像空格的字符,但从代码上讲,它不是。换句话说,SearchView 不是空的。空字符串或空" "不起作用,因为基本 SearchView 使用修剪,加上用户可能希望搜索以空格结尾或开头的文本。但据我所知,用户无法输入u00A0字符。

然后,您需要做的就是覆盖getQuery以在自定义SearchView中return super.getQuery.replace("u00A0", "")

这是一个非常肮脏的黑客,但它按预期正常工作,即使没有在 SearchView 中输入(或输入然后编辑)文本,也可以启用提交操作。

它以反射方式获取对内部 TextView 编辑器操作侦听器的访问权限,将其包装在自定义侦听器中,在该侦听器中,它将调用委托给处理程序,最后将其设置为内部 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);
    }

正如其他人所提到的,这种行为是故意的。 我放弃了OnQueryChangeListener的解决方案,并决定通过在 SearchView 的 EditText 上实现OnEditorActionListener来解决,您可以使用 R.id.search_src_text 来处理。 只要您setImeOptions搜索视图以EditorInfo.IME_ACTION_SEARCH就可以处理单击键盘搜索按钮。 有关更多详细信息,请参阅此SO答案。

我可以简单地通过以这种方式实现setOnQueryTextListener来做到这一点:

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

我的 loadLocalData 方法在哪里

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

即使您使用"X"按钮清除文本,此解决方案也会清除查询

我遇到了同样的问题,因为不支持空查询,我不得不下载并使用 ActionBarSherlock,然后修改 onSubmitQuery() 方法。

这就是我的onSubmitQuery()现在的样子

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

希望这有帮助。

这是一个用 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()
    }
}

您可以使用setOnEmptySubmitListener设置自定义侦听器,以便区分事件。

您可以自定义要响应的 actionId,在本例中,我的 XML 中有带有此android:imeOptions="actionDone|flagNoExtractUi"的 EmptySubmitSearchView

不能覆盖此行为。解决方法可能是在用户退出搜索视图时清除筛选器。

你可以使用OnCloseListener来实现这一点。但是,这也可能导致问题,具体取决于您开发的最低 API 级别。

另一种选择是通过 TextWatcher 手动触发 onQueryTextChange 方法:

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

这一切都与此处放弃的所有默认xml文件有关,这不是本答案的重点。这是我选择使用的解决方法,请随意使用其他人

就我而言,我只是想让用户清除他的查询,因为它在 API 搜索中用作关键字,所以最简单的想法是:

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

其中用户查询是我用于搜索等的变量。

希望它能帮助某人:)

这是 samvel1024 的答案将其转换为 Kotlin。您可能需要将IME_ACTION_GO更改为用于键盘"开始"按钮的任何内容。只需在页面初始化期间运行此方法即可。

/**
 * Business: User should be allowed to perform an empty search.
 * SearchView does not cause OnQueryTextChange to fire when the box is empty.
 * To create a listener method for this scenario, we use reflection to gain access to the SearchView's inner TextView.
 */
private fun enableEmptySearch(searchView: SearchView) {
    try {
        val searchViewClass = searchView::class.java
        val currentListenerField: Field = searchViewClass.getDeclaredField("mOnEditorActionListener")
        currentListenerField.isAccessible = true
        val previousListener: TextView.OnEditorActionListener = currentListenerField.get(searchView) as TextView.OnEditorActionListener
        val newListener: TextView.OnEditorActionListener = TextView.OnEditorActionListener { v, actionId, event ->
            if (actionId == EditorInfo.IME_ACTION_GO && v.text.isEmpty()) {
                querySubmit()
            }
            previousListener.onEditorAction(v, actionId, event)
        }
        val innerTextViewField: Field = searchViewClass.getDeclaredField("mSearchSrcTextView")
        innerTextViewField.isAccessible = true
        (innerTextViewField.get(searchView) as TextView).setOnEditorActionListener(newListener) // Allow user to tap the "GO" button when the SearchView is empty.
    } catch (ignored: Exception) {
        // If a major change occurs to android SDK, internal fields mSearchSrcTextView or mOnEditorActionListener might not exist.
        // This exception will prevent this additional feature from functioning, but not crash the app or cause any other issues.
    }
}
<</div> div class="one_answers">

对于 Koltin 用户:

只需使用以下方法代替searchView.setOnQueryTextListener

val searchPlate = searchView.findViewById<EditText>(R.id.search_src_text)
        searchPlate.setOnEditorActionListener { _, actionId, _ ->
            if (actionId == EditorInfo.IME_ACTION_SEARCH) {
                searchYourItems(searchView.query.toString()) // your code goes here
            }
            false
        }

相关内容

  • 没有找到相关文章

最新更新