我正在使用Android 4.1.2。我有一个SearchView
小部件ActionBar
。SearchView.OnQueryTextListener
来自 android 开发者网站的文档说明onQueryTextSubmit
当用户提交查询时触发/调用。这可能是由于键盘上的按键或按下提交按钮所致。”
如果搜索查询为空,则不会发生这种情况。我需要这个来触发一个空查询以清除 ListView 的搜索过滤器。这是一个错误还是我做错了什么?
我正在使用Android 4.1.2。我有一个SearchView
小部件ActionBar
。SearchView.OnQueryTextListener
来自 android 开发者网站的文档说明onQueryTextSubmit
当用户提交查询时触发/调用。这可能是由于键盘上的按键或按下提交按钮所致。”
如果搜索查询为空,则不会发生这种情况。我需要这个来触发一个空查询以清除 ListView 的搜索过滤器。这是一个错误还是我做错了什么?
这不是错误,源代码故意检查 null 和空值:
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;
}
});
我遇到了同样的问题,最终得到了以下解决方案:custom 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 测试。
我对 SearchView 有同样的问题。我的解决方案包括设置 SearchView 的样式,如指南http://novoda.com/blog/styling-the-actionbar-searchview/中所示,并为 EditText 设置 OnEditorActionListener(当用户按 Enter 时如何触发操作?)是 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
字符。
然后您需要做的就是return super.getQuery.replace("\u00A0", "")
在您的自定义 SearchView中覆盖 getQuery
这是一个非常肮脏的 hack,但是它可以按预期正常工作,即使在 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
并决定通过OnEditorActionListener
在 SearchView 上实现来解决问题EditText
,您可以使用R.id.search_src_text
. 只要你setImeOptions
的SearchView 到EditorInfo.IME_ACTION_SEARCH
你就可以处理键盘搜索按钮的点击。有关更多详细信息,请参阅此 SO 答案。
我遇到了同样的问题,因为不支持空查询,所以我必须下载并使用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();
}
}
希望这可以帮助。
我可以通过以这种方式实现 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”按钮清除文本,此解决方案也会清除您的查询
这是一个用 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 中有 EmptySubmitSearchView 与此android:imeOptions="actionDone|flagNoExtractUi"
另一种选择是通过 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 文件一起使用,这不是这个答案的重点。这是我选择使用的解决方法,请随意使用其他人
您不能覆盖此行为。当用户退出搜索视图时,一种解决方法可能是清除过滤器。
您可以为此使用OnCloseListener。但是,这也可能会导致问题,具体取决于您开发的最低 API 级别。
这是 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.
}
}
就我而言,我只是想让用户清除他的查询,因为它在 API 搜索中用作关键字,所以最简单的想法是:
searchView.setOnSearchClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
userQuery = "";
}
});
其中 userQuery 是我用于搜索等的变量。
希望它可以帮助某人:)