Android SearchView.OnQueryTextListener OnQueryTextSubmit не запускается в пустой строке запроса
Я использую Android 4.1.2. У меня есть виджет SearchView на ActionBar
. Документация на SearchView.OnQueryTextListener
с сайта разработчика Android указывает, что onQueryTextSubmit
запускается, когда "Вызывается, когда пользователь отправляет запрос. Это может быть связано с нажатием клавиши на клавиатуре или из-за нажатия кнопки отправки".
Это не происходит, если поисковый запрос пуст. Мне нужно, чтобы он запускал пустой запрос, чтобы очистить фильтр поиска ListView. Является ли это ошибкой или я что-то делаю неправильно?
Ответы
Ответ 1
Это не ошибка, исходный код преднамеренно проверяет пустые и пустые значения:
private void onSubmitQuery() {
CharSequence query = mQueryTextView.getText();
if (query != null && TextUtils.getTrimmedLength(query) > 0) {
Однако вы должны иметь возможность использовать обратный вызов OnQueryTextChange для очистки фильтров ListView, когда пользователь очищает поиск EditText.
Ответ 2
Более легкая работа:
используйте 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;
}
});
Ответ 3
У меня была такая же проблема, и в итоге получилось следующее решение: 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.
}
};
Протестировано на АБС 4.3.
Ответ 4
У меня была такая же проблема с SearchView. Мое решение, которое состоит из стилизации SearchView, как показано в руководстве http://novoda.com/blog/styling-the-actionbar-searchview/, и установки OnEditorActionListener для EditText (как вызвать действие, когда пользователь нажал клавишу ввода?), Которое является частью 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;
}});
Ответ 5
Как отмечали другие, это поведение преднамеренно. Я отказался от решения для OnQueryChangeListener
и решил обходным путем, выполнив OnEditorActionListener
в SearchView EditText
, который вы можете получить при использовании R.id.search_src_text
. Пока вы setImeOptions
от SearchView до EditorInfo.IME_ACTION_SEARCH
, вы можете обрабатывать щелчок по кнопке поиска на клавиатуре. Подробнее см. этот SO ответ.
Ответ 6
У меня была та же проблема, поскольку пустой запрос не поддерживается. Мне пришлось загрузить и использовать 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();
}
}
Надеюсь, что это поможет.
Ответ 7
Это очень грязный хак, однако он работает корректно, как и ожидалось, что позволяет отправить действие, даже если в 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);
}
Ответ 8
Вы не можете перезаписать это поведение.
Обходной путь может заключаться в очистке фильтра, когда пользователь выходит из поиска.
Для этого вы можете использовать OnCloseListener.
Однако это может также вызвать проблемы, в зависимости от минимального уровня API, для которого вы разрабатываете.
Ответ 9
Другой вариант - запустить метод onQueryTextChange вручную через 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;
}
}
Это все идет со всеми файлами xml по умолчанию, которые были отброшены здесь, это не точка этого ответа. Это обходной путь, который я предпочитаю использовать, не стесняйтесь использовать других.
Ответ 10
Я могу сделать это просто, выполнив 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;
}
});
Где мой метод loadLocalDatap >
//query my DB
products = ProductDAO.findByIdList(idList);
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
listView.setLayoutManager(layoutManager);
listView.setAdapter(<YOURADAPTER>)
Это решение очищает ваш запрос, даже если вы очищаете текст с помощью кнопки "X"
Ответ 11
В моем случае я просто хотел разрешить пользователю очищать свой запрос, поскольку он использовался как ключевое слово в поиске API, поэтому самая простая идея:
searchView.setOnSearchClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
userQuery = "";
}
});
где userQuery - моя переменная, используемая для поиска и т.д.
Надеюсь, это поможет кому-то:)
Ответ 12
Это старый поток, но я нашел другое решение (код Kotlin, но работает и на Java):
override fun onQueryTextChange(newText: String?): Boolean {
if(newText == null || newText.isEmpty())
searchView.setQuery("\u00A0", false)
return true
}
\u00A0
- это символ, который выглядит как пробел, но с точки зрения кода это не так. Другими словами SearchView не является пустым. Пустая строка или " "
не будут работать, потому что базовый SearchView использует обрезку, плюс пользователь может захотеть найти текст, заканчивающийся или начинающийся с пробела. Но, насколько я знаю, пользователи не могут вводить \u00A0
.
Тогда все, что вам нужно сделать, это переопределить getQuery для return super.getQuery.replace("\u00A0", "")
в ваш пользовательский SearchView.